diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4a354df64..53c13eb063 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -418,6 +418,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingSetDate.cpp displayapp/screens/settings/SettingSetTime.cpp displayapp/screens/settings/SettingChimes.cpp + displayapp/screens/settings/SettingTheme.cpp displayapp/screens/settings/SettingShakeThreshold.cpp displayapp/screens/settings/SettingBluetooth.cpp displayapp/screens/settings/SettingOTA.cpp diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 35330fb7f7..c04299126a 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -52,9 +52,11 @@ #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" #include "displayapp/screens/settings/SettingOTA.h" +#include "displayapp/screens/settings/SettingTheme.h" #include "libs/lv_conf.h" #include "UserApps.h" +#include "displayapp/InfiniTimeTheme.h" #include @@ -521,6 +523,14 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio currentScreen.reset(nullptr); SetFullRefresh(direction); + // Reset screen background color based on app type + // Watch faces keep black background, other apps use theme color + if (app == Apps::Clock) { + lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + } else { + lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Colors::page_bg); + } + switch (app) { case Apps::Launcher: { std::array apps; @@ -633,6 +643,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio case Apps::SettingOTA: currentScreen = std::make_unique(this, settingsController); break; + case Apps::SettingTheme: + currentScreen = std::make_unique(this); + break; case Apps::BatteryInfo: currentScreen = std::make_unique(batteryController); break; diff --git a/src/displayapp/InfiniTimeTheme.cpp b/src/displayapp/InfiniTimeTheme.cpp index 6795647e1b..7df87a82ca 100644 --- a/src/displayapp/InfiniTimeTheme.cpp +++ b/src/displayapp/InfiniTimeTheme.cpp @@ -1,5 +1,8 @@ #include "displayapp/InfiniTimeTheme.h" +#include +#include "components/fs/FS.h" #include +#include // Replace LV_DPX with a constexpr version using a constant LV_DPI #undef LV_DPX @@ -11,6 +14,184 @@ namespace { } return std::max(((LV_DPI * n + 80) / 160), 1); /*+80 for rounding*/ } + + /** + * Parse hex color string (RRGGBB format) to lv_color_t + * Returns the parsed color or defaultColor if parsing fails + */ + lv_color_t parseHexColor(const char* hexStr, lv_color_t defaultColor) { + if (!hexStr || std::strlen(hexStr) < 6) { + return defaultColor; + } + + char* endptr; + uint32_t value = std::strtoul(hexStr, &endptr, 16); + + // Check if conversion was successful and we consumed all characters + if (endptr == hexStr || *endptr != '\0' || value > 0xFFFFFF) { + return defaultColor; + } + + uint8_t r = (value >> 16) & 0xFF; + uint8_t g = (value >> 8) & 0xFF; + uint8_t b = value & 0xFF; + + lv_color_t result = LV_COLOR_MAKE(r, g, b); + + return result; + } + + /** + * Parse a configuration line in format: KEY=VALUE + * Lines starting with # are treated as comments + * Returns true if the line was successfully parsed + */ + bool parseLine(const char* line, char* key, char* value, size_t maxKeyLen, size_t maxValueLen) { + // Skip whitespace and comments + while (*line == ' ' || *line == '\t') { + line++; + } + if (*line == '#' || *line == '\0' || *line == '\n' || *line == '\r') { + return false; + } + + // Parse key + size_t keyLen = 0; + while (*line != '=' && *line != '\0' && *line != '\n' && keyLen < maxKeyLen - 1) { + char c = *line++; + // Trim trailing whitespace from key + if (c != ' ' && c != '\t') { + key[keyLen++] = c; + } else if (keyLen > 0 && key[keyLen - 1] != ' ') { + key[keyLen++] = c; + } + } + + // Trim trailing whitespace from key + while (keyLen > 0 && (key[keyLen - 1] == ' ' || key[keyLen - 1] == '\t')) { + keyLen--; + } + + key[keyLen] = '\0'; + + if (*line != '=' || keyLen == 0) { + return false; + } + line++; // Skip '=' + + // Skip leading whitespace in value + while (*line == ' ' || *line == '\t') { + line++; + } + + // Parse value + size_t valueLen = 0; + while (*line != '\0' && *line != '\n' && *line != '\r' && valueLen < maxValueLen - 1) { + value[valueLen++] = *line++; + } + value[valueLen] = '\0'; + + return true; + } + + /** + * Load colors from /themes/theme.cfg file in LittleFS + * File format: + * # This is a comment + * bg=5D697E + * accent=383838 + * accent_dark=181818 + * highlight=00B000 + * color_primary=FFFFFF + * color_secondary=808080 + */ + void loadThemeConfig(Pinetime::Controllers::FS* filesystem) { + if (!filesystem) { + return; + } + + lfs_file_t file; + if (filesystem->FileOpen(&file, "/themes/theme.cfg", LFS_O_RDONLY) != LFS_ERR_OK) { + NRF_LOG_INFO("loadThemeConfig: Failed to open /themes/theme.cfg"); + return; + } + + // Read the entire file into a buffer (reasonable limit for config file) + constexpr size_t maxConfigSize = 1024; + uint8_t buffer[maxConfigSize]; + lfs_ssize_t bytesRead = filesystem->FileRead(&file, buffer, maxConfigSize - 1); + filesystem->FileClose(&file); + + if (bytesRead <= 0) { + return; + } + + buffer[bytesRead] = '\0'; + const char* configData = reinterpret_cast(buffer); + + // Parse the configuration file line by line + char line[256]; + char key[64]; + char value[64]; + size_t lineStart = 0; + + while (lineStart < static_cast(bytesRead)) { + size_t lineEnd = lineStart; + // Find the end of the line + while (lineEnd < static_cast(bytesRead) && configData[lineEnd] != '\n') { + lineEnd++; + } + + size_t lineLen = lineEnd - lineStart; + if (lineLen >= sizeof(line)) { + lineLen = sizeof(line) - 1; + } + + std::memcpy(line, &configData[lineStart], lineLen); + line[lineLen] = '\0'; + + if (parseLine(line, key, value, sizeof(key), sizeof(value))) { + if (std::strcmp(key, "accent_light") == 0) { + Colors::accent_light = parseHexColor(value, Colors::accent_light); + } else if (std::strcmp(key, "accent") == 0) { + Colors::accent = parseHexColor(value, Colors::accent); + } else if (std::strcmp(key, "accent_dark") == 0) { + Colors::accent_dark = parseHexColor(value, Colors::accent_dark); + } else if (std::strcmp(key, "highlight") == 0) { + Colors::highlight = parseHexColor(value, Colors::highlight); + } else if (std::strcmp(key, "text_primary") == 0) { + Colors::text_primary = parseHexColor(value, Colors::text_primary); + } else if (std::strcmp(key, "text_header") == 0) { + Colors::text_header = parseHexColor(value, Colors::text_header); + } else if (std::strcmp(key, "page_bg") == 0) { + Colors::page_bg = parseHexColor(value, Colors::page_bg); + } else if (std::strcmp(key, "icon") == 0) { + Colors::icon = parseHexColor(value, Colors::icon); + } + } + + lineStart = lineEnd + 1; // Skip the newline character + } + } +} + +static Pinetime::Controllers::FS* themeFilesystem = nullptr; + +// Helper function to recursively refresh styles of an object and all its children +static void refresh_object_tree(lv_obj_t* obj) { + if (obj == nullptr) { + return; + } + + // Refresh this object + lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); + + // Recursively refresh all children + lv_obj_t* child = lv_obj_get_child(obj, nullptr); + while (child != nullptr) { + refresh_object_tree(child); + child = lv_obj_get_child(obj, child); + } } static void theme_apply(lv_obj_t* obj, lv_theme_style_t name); @@ -54,7 +235,7 @@ static void style_init_reset(lv_style_t* style) { static void basic_init() { style_init_reset(&style_bg); lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, Colors::page_bg); lv_style_set_text_font(&style_bg, LV_STATE_DEFAULT, theme.font_normal); style_init_reset(&style_box); @@ -63,24 +244,24 @@ static void basic_init() { lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal); style_init_reset(&style_label_white); - lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_text_color(&style_label_white, LV_STATE_DEFAULT, Colors::text_primary); lv_style_set_text_color(&style_label_white, LV_STATE_DISABLED, LV_COLOR_GRAY); style_init_reset(&style_btn); lv_style_set_radius(&style_btn, LV_STATE_DEFAULT, 10); lv_style_set_bg_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, Colors::accent_light); lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, Colors::highlight); - lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, Colors::bgDark); + lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, Colors::accent_dark); - lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, Colors::text_primary); lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); lv_style_set_pad_all(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15)); style_init_reset(&style_icon); - lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, Colors::text_primary); style_init_reset(&style_bar_indic); lv_style_set_bg_opa(&style_bar_indic, LV_STATE_DEFAULT, LV_OPA_COVER); @@ -96,9 +277,9 @@ static void basic_init() { style_init_reset(&style_list_btn); lv_style_set_bg_opa(&style_list_btn, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&style_list_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_text_color(&style_list_btn, LV_STATE_DEFAULT, Colors::accent_light); lv_style_set_text_color(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE); - lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_image_recolor(&style_list_btn, LV_STATE_DEFAULT, Colors::accent_light); lv_style_set_image_recolor(&style_list_btn, LV_STATE_CHECKED, LV_COLOR_WHITE); lv_style_set_pad_left(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25); lv_style_set_pad_right(&style_list_btn, LV_STATE_DEFAULT, LV_HOR_RES / 25); @@ -115,11 +296,11 @@ static void basic_init() { style_init_reset(&style_ddlist_selected); lv_style_set_bg_opa(&style_ddlist_selected, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_bg_color(&style_ddlist_selected, LV_STATE_DEFAULT, Colors::accent_light); style_init_reset(&style_sw_bg); lv_style_set_bg_opa(&style_sw_bg, LV_STATE_DEFAULT, LV_OPA_COVER); - lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_bg_color(&style_sw_bg, LV_STATE_DEFAULT, Colors::accent_light); lv_style_set_radius(&style_sw_bg, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); style_init_reset(&style_sw_indic); @@ -143,12 +324,12 @@ static void basic_init() { lv_style_set_pad_all(&style_slider_knob, LV_STATE_PRESSED, 14); style_init_reset(&style_arc_indic); - lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, Colors::lightGray); + lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, Colors::accent_light); lv_style_set_line_width(&style_arc_indic, LV_STATE_DEFAULT, LV_DPX(25)); lv_style_set_line_rounded(&style_arc_indic, LV_STATE_DEFAULT, true); style_init_reset(&style_arc_bg); - lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, Colors::bg); + lv_style_set_line_color(&style_arc_bg, LV_STATE_DEFAULT, Colors::accent_dark); lv_style_set_line_width(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(25)); lv_style_set_line_rounded(&style_arc_bg, LV_STATE_DEFAULT, true); lv_style_set_pad_all(&style_arc_bg, LV_STATE_DEFAULT, LV_DPX(5)); @@ -206,18 +387,18 @@ static void basic_init() { /** * Initialize the default - * @param color_primary the primary color of the theme - * @param color_secondary the secondary color for the theme - * @param flags ORed flags starting with `LV_THEME_DEF_FLAG_...` - * @param font_small pointer to a small font - * @param font_normal pointer to a normal font - * @param font_subtitle pointer to a large font - * @param font_title pointer to a extra large font * @return a pointer to reference this theme later */ -lv_theme_t* lv_pinetime_theme_init() { - theme.color_primary = LV_COLOR_WHITE; - theme.color_secondary = LV_COLOR_GRAY; +lv_theme_t* lv_pinetime_theme_init(Pinetime::Controllers::FS* filesystem) { + + // Set the filesystem pointer if provided + if (filesystem != nullptr) { + themeFilesystem = filesystem; + loadThemeConfig(filesystem); + } + + theme.color_primary = Colors::text_primary; + theme.color_secondary = Colors::text_header; theme.font_small = &jetbrains_mono_bold_20; theme.font_normal = &jetbrains_mono_bold_20; theme.font_subtitle = &jetbrains_mono_bold_20; @@ -233,6 +414,36 @@ lv_theme_t* lv_pinetime_theme_init() { return &theme; } +void lv_pinetime_theme_set_filesystem(Pinetime::Controllers::FS* filesystem) { + + themeFilesystem = filesystem; + + // If theme was already initialized and we now have a filesystem, try to reload colors + if (inited && filesystem != nullptr) { + loadThemeConfig(filesystem); + } +} + +void lv_pinetime_theme_reload_config() { + if (themeFilesystem != nullptr) { + loadThemeConfig(themeFilesystem); + + // Update the theme struct with new colors + theme.color_primary = Colors::text_primary; + theme.color_secondary = Colors::text_header; + + // Reinitialize the theme styles with the new colors + basic_init(); + + // Refresh all objects on screen to apply the new styles + lv_obj_t* scr = lv_scr_act(); + if (scr != nullptr) { + refresh_object_tree(scr); + lv_obj_invalidate(scr); + } + } +} + static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) { lv_style_list_t* list; @@ -417,3 +628,24 @@ static void theme_apply(lv_obj_t* obj, lv_theme_style_t name) { lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); } + +bool lv_pinetime_theme_is_custom_loaded() { + if (themeFilesystem == nullptr) { + return false; + } + + // Simple heuristic: if primary color differs from white, we likely loaded custom theme + // White is the default color_primary in the header + if (Colors::text_primary.full != LV_COLOR_WHITE.full) { + return true; + } + + // Additional check: if bg color differs from default + // Default is LV_COLOR_MAKE(0x5d, 0x69, 0x7e) + const lv_color_t defaultBg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); + if (Colors::accent_light.full != defaultBg.full) { + return true; + } + + return false; +} diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 0690b09912..ca64742fd2 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -2,6 +2,13 @@ #include +// Forward declaration +namespace Pinetime { + namespace Controllers { + class FS; + } +} + namespace Colors { static constexpr lv_color_t deepOrange = LV_COLOR_MAKE(0xff, 0x40, 0x0); static constexpr lv_color_t orange = LV_COLOR_MAKE(0xff, 0xb0, 0x0); @@ -9,21 +16,39 @@ namespace Colors { static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff); static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0); - static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); - static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38); - static constexpr lv_color_t bgDark = LV_COLOR_MAKE(0x18, 0x18, 0x18); - static constexpr lv_color_t highlight = green; + // Configurable colors that can be loaded from storage + inline lv_color_t accent_light = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); + inline lv_color_t accent = LV_COLOR_MAKE(0x38, 0x38, 0x38); + inline lv_color_t accent_dark = LV_COLOR_MAKE(0x18, 0x18, 0x18); + inline lv_color_t highlight = green; + inline lv_color_t text_primary = LV_COLOR_WHITE; + inline lv_color_t text_header = LV_COLOR_GRAY; + inline lv_color_t page_bg = LV_COLOR_BLACK; + inline lv_color_t icon = orange; }; /** - * Initialize the default - * @param color_primary the primary color of the theme - * @param color_secondary the secondary color for the theme - * @param flags ORed flags starting with `LV_THEME_DEF_FLAG_...` - * @param font_small pointer to a small font - * @param font_normal pointer to a normal font - * @param font_subtitle pointer to a large font - * @param font_title pointer to a extra large font + * Initialize the default theme + * @param filesystem FS pointer to load custom colors from, can be nullptr * @return a pointer to reference this theme later */ -lv_theme_t* lv_pinetime_theme_init(); +lv_theme_t* lv_pinetime_theme_init(Pinetime::Controllers::FS* filesystem = nullptr); + +/** + * Set the filesystem reference for theme color loading + * @param filesystem FS reference to load colors from config file + */ +void lv_pinetime_theme_set_filesystem(Pinetime::Controllers::FS* filesystem); + +/** + * Reload theme configuration from the filesystem + * Call this after the filesystem is fully initialized if theme was initialized before + */ +void lv_pinetime_theme_reload_config(); + +/** + * Check if a custom theme is currently loaded from the filesystem + * Returns true if filesystem is set and theme.cfg file exists and was loaded + * Returns false if using built-in colors + */ +bool lv_pinetime_theme_is_custom_loaded(); diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp index f9791c302d..d77a3322cc 100644 --- a/src/displayapp/LittleVgl.cpp +++ b/src/displayapp/LittleVgl.cpp @@ -10,8 +10,8 @@ using namespace Pinetime::Components; namespace { - void InitTheme() { - lv_theme_t* theme = lv_pinetime_theme_init(); + void InitTheme(Pinetime::Controllers::FS* filesystem) { + lv_theme_t* theme = lv_pinetime_theme_init(filesystem); lv_theme_set_act(theme); } @@ -78,10 +78,10 @@ LittleVgl::LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Controllers::FS& void LittleVgl::Init() { lv_init(); - InitTheme(); + InitFileSystem(); + InitTheme(&filesystem); InitDisplay(); InitTouchpad(); - InitFileSystem(); } void LittleVgl::InitDisplay() { diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index d440b598d1..d4025ab50c 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -45,6 +45,7 @@ namespace Pinetime { SettingShakeThreshold, SettingBluetooth, SettingOTA, + SettingTheme, Error }; diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index 4cf4392157..71182bfeca 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -84,7 +84,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController, lv_label_set_text_static(txtStop, Symbols::stop); lv_obj_set_hidden(btnStop, true); - static constexpr lv_color_t bgColor = Colors::bgAlt; + lv_color_t bgColor = Colors::accent; btnRecur = lv_btn_create(lv_scr_act(), nullptr); btnRecur->user_data = this; @@ -303,4 +303,4 @@ void Alarm::ToggleRecurrence() { alarmController.SetRecurrence(AlarmController::RecurType::None); } SetRecurButtonState(); -} +} \ No newline at end of file diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index 16845d53e7..e1f0d2d402 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -18,7 +18,7 @@ BatteryInfo::BatteryInfo(const Pinetime::Controllers::Battery& batteryController lv_obj_align(chargingArc, nullptr, LV_ALIGN_CENTER, 0, -30); lv_arc_set_value(chargingArc, batteryPercent); lv_obj_set_style_local_bg_opa(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0); - lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, Colors::accent_dark); lv_obj_set_style_local_border_width(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2); lv_obj_set_style_local_radius(chargingArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_line_color(chargingArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_LIME); diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index a1f093830c..4f396128d5 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -39,7 +39,7 @@ Calculator::Calculator() { lv_btnmatrix_set_map(buttonMatrix, const_cast(buttonMap)); lv_btnmatrix_set_one_check(buttonMatrix, true); lv_obj_set_size(buttonMatrix, 238, 180); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_style_local_pad_inner(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_top(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_bottom(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); @@ -208,24 +208,24 @@ void Calculator::UpdateOperation() const { case '+': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::accent); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); break; case '-': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::accent); lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); break; case '*': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::accent); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); break; case '/': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::accent); lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); break; diff --git a/src/displayapp/screens/CheckboxList.cpp b/src/displayapp/screens/CheckboxList.cpp index 9eb80bbad4..2c28bb5f47 100644 --- a/src/displayapp/screens/CheckboxList.cpp +++ b/src/displayapp/screens/CheckboxList.cpp @@ -1,6 +1,7 @@ #include "displayapp/DisplayApp.h" #include "displayapp/screens/CheckboxList.h" #include "displayapp/screens/Styles.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -23,8 +24,8 @@ CheckboxList::CheckboxList(const uint8_t screenID, options {options}, value {originalValue}, pageIndicator(screenID, numScreens) { - // Set the background to Black - lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + // Set the background to use theme color + lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Colors::page_bg); if (numScreens > 1) { pageIndicator.Create(); @@ -43,12 +44,13 @@ CheckboxList::CheckboxList(const uint8_t screenID, lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::text_header); lv_label_set_text_static(title, optionsTitle); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 15); lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::icon); lv_label_set_text_static(icon, optionsSymbol); lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); diff --git a/src/displayapp/screens/FirmwareUpdate.cpp b/src/displayapp/screens/FirmwareUpdate.cpp index 7d00ef3921..ed7ad98fe4 100644 --- a/src/displayapp/screens/FirmwareUpdate.cpp +++ b/src/displayapp/screens/FirmwareUpdate.cpp @@ -13,7 +13,7 @@ FirmwareUpdate::FirmwareUpdate(const Pinetime::Controllers::Ble& bleController) lv_obj_align(titleLabel, nullptr, LV_ALIGN_IN_TOP_MID, 0, 50); bar1 = lv_bar_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_style_local_bg_opa(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); lv_obj_set_style_local_radius(bar1, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_size(bar1, 200, 30); diff --git a/src/displayapp/screens/List.cpp b/src/displayapp/screens/List.cpp index 264b4fc98b..35407984c4 100644 --- a/src/displayapp/screens/List.cpp +++ b/src/displayapp/screens/List.cpp @@ -19,13 +19,13 @@ List::List(uint8_t screenID, std::array& applications) : app {app}, settingsController {settingsController}, pageIndicator(screenID, numScreens) { - // Set the background to Black - lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_make(0, 0, 0)); - settingsController.SetSettingsMenu(screenID); pageIndicator.Create(); + // Set the background to use theme color + lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Colors::page_bg); + lv_obj_t* container = lv_cont_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); @@ -45,7 +45,7 @@ List::List(uint8_t screenID, static constexpr int btnHeight = (LV_HOR_RES_MAX - ((MAXLISTITEMS - 1) * innerPad)) / MAXLISTITEMS; itemApps[i] = lv_btn_create(container, nullptr); lv_obj_set_style_local_radius(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, btnHeight / 3); - lv_obj_set_style_local_bg_color(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_width(itemApps[i], LV_HOR_RES - 8); lv_obj_set_height(itemApps[i], btnHeight); lv_obj_set_event_cb(itemApps[i], ButtonEventHandler); @@ -54,7 +54,7 @@ List::List(uint8_t screenID, lv_obj_set_style_local_clip_corner(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, true); lv_obj_t* icon = lv_label_create(itemApps[i], nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::icon); lv_label_set_text_static(icon, applications[i].icon); lv_label_set_long_mode(icon, LV_LABEL_LONG_CROP); lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp index e1441460f7..0aea1f6314 100644 --- a/src/displayapp/screens/Music.cpp +++ b/src/displayapp/screens/Music.cpp @@ -53,7 +53,7 @@ Music::Music(Pinetime::Controllers::MusicService& music) : musicService(music) { lv_style_init(&btn_style); lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, 20); - lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::bgAlt); + lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::accent); btnVolDown = lv_btn_create(lv_scr_act(), nullptr); btnVolDown->user_data = this; diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 837c4683aa..bbd3a8c69c 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -133,7 +133,7 @@ void Notifications::DismissToBlack() { // create black transition screen to let the notification dismiss to blackness lv_obj_t* blackBox = lv_obj_create(lv_scr_act(), nullptr); lv_obj_set_size(blackBox, LV_HOR_RES, LV_VER_RES); - lv_obj_set_style_local_bg_color(blackBox, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_bg_color(blackBox, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, Colors::page_bg); dismissingNotification = true; } @@ -265,13 +265,13 @@ Notifications::NotificationItem::NotificationItem(const char* title, : alertNotificationService {alertNotificationService}, motorController {motorController} { container = lv_cont_create(lv_scr_act(), nullptr); lv_obj_set_size(container, LV_HOR_RES, LV_VER_RES); - lv_obj_set_style_local_bg_color(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_bg_color(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, Colors::page_bg); lv_obj_set_style_local_pad_all(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_border_width(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); subject_container = lv_cont_create(container, nullptr); - lv_obj_set_style_local_bg_color(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_style_local_pad_all(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); lv_obj_set_style_local_pad_inner(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); lv_obj_set_style_local_border_width(subject_container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); @@ -286,7 +286,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, lv_obj_align(alert_count, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 16); lv_obj_t* alert_type = lv_label_create(container, nullptr); - lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); + lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::text_header); if (title == nullptr) { lv_label_set_text_static(alert_type, "Notification"); } else { diff --git a/src/displayapp/screens/Steps.cpp b/src/displayapp/screens/Steps.cpp index 2e73dab512..e887e38ec5 100644 --- a/src/displayapp/screens/Steps.cpp +++ b/src/displayapp/screens/Steps.cpp @@ -22,7 +22,7 @@ Steps::Steps(Controllers::MotionController& motionController, Controllers::Setti stepsArc = lv_arc_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_opa(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0); - lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_style_local_border_width(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 2); lv_obj_set_style_local_radius(stepsArc, LV_ARC_PART_BG, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_line_color(stepsArc, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, Colors::blue); @@ -64,7 +64,7 @@ Steps::Steps(Controllers::MotionController& motionController, Controllers::Setti lv_obj_set_event_cb(resetBtn, lap_event_handler); lv_obj_set_size(resetBtn, 120, 50); lv_obj_set_style_local_radius(resetBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_style_local_bg_color(resetBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(resetBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_align(resetBtn, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); resetButtonLabel = lv_label_create(resetBtn, nullptr); lv_label_set_text_static(resetButtonLabel, "Reset"); diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index 8d029019b6..74ae2b9e4d 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -116,8 +116,8 @@ void StopWatch::DisplayPaused() { void StopWatch::DisplayStarted() { lv_obj_set_state(time, LV_STATE_DEFAULT); lv_obj_set_state(msecTime, LV_STATE_DEFAULT); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); - lv_obj_set_style_local_bg_color(btnStopLap, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); + lv_obj_set_style_local_bg_color(btnStopLap, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_label_set_text_static(txtPlayPause, Symbols::pause); lv_label_set_text_static(txtStopLap, Symbols::lapsFlag); diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index 45f715b55a..2538ecc870 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -70,9 +70,9 @@ Tile::Tile(uint8_t screenID, lv_obj_align(btnm1, nullptr, LV_ALIGN_CENTER, 0, 10); lv_obj_set_style_local_radius(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, 20); - lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, LV_OPA_50); - lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, Colors::bgDark); + lv_obj_set_style_local_bg_color(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DISABLED, Colors::accent_dark); lv_obj_set_style_local_pad_all(btnm1, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 0); lv_obj_set_style_local_pad_inner(btnm1, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 10); diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index 749d985933..1c289370bc 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -56,7 +56,7 @@ Timer::Timer(Controllers::Timer& timerController, Controllers::MotorController& btnPlayPause = lv_btn_create(btnObjectMask, nullptr); btnPlayPause->user_data = this; lv_obj_set_style_local_radius(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_event_cb(btnPlayPause, btnEventHandler); lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50); @@ -159,14 +159,14 @@ void Timer::SetTimerRunning() { minuteCounter.HideControls(); secondCounter.HideControls(); lv_label_set_text_static(txtPlayPause, "Pause"); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); } void Timer::SetTimerStopped() { minuteCounter.ShowControls(); secondCounter.ShowControls(); lv_label_set_text_static(txtPlayPause, "Start"); - lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent_light); } void Timer::SetTimerRinging() { diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 0e44df0349..bfafc5931a 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -35,13 +35,13 @@ Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleW lv_obj_set_auto_realign(temperature, true); minTemperature = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); + lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::accent_light); lv_label_set_text(minTemperature, ""); lv_obj_align(minTemperature, temperature, LV_ALIGN_OUT_LEFT_MID, -10, 0); lv_obj_set_auto_realign(minTemperature, true); maxTemperature = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(maxTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); + lv_obj_set_style_local_text_color(maxTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::accent_light); lv_label_set_text(maxTemperature, ""); lv_obj_align(maxTemperature, temperature, LV_ALIGN_OUT_RIGHT_MID, 10, 0); lv_obj_set_auto_realign(maxTemperature, true); diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index c5c3071aef..470a884fe2 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -60,7 +60,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app, lv_style_init(&btn_style); lv_style_set_radius(&btn_style, LV_STATE_DEFAULT, buttonHeight / 4); - lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::bgAlt); + lv_style_set_bg_color(&btn_style, LV_STATE_DEFAULT, Colors::accent); btn1 = lv_btn_create(lv_scr_act(), nullptr); btn1->user_data = this; diff --git a/src/displayapp/screens/settings/SettingSetDate.cpp b/src/displayapp/screens/settings/SettingSetDate.cpp index 93a8da4d27..83dcedb83b 100644 --- a/src/displayapp/screens/settings/SettingSetDate.cpp +++ b/src/displayapp/screens/settings/SettingSetDate.cpp @@ -3,6 +3,7 @@ #include #include #include "displayapp/DisplayApp.h" +#include "displayapp/InfiniTimeTheme.h" #include "displayapp/screens/Symbols.h" using namespace Pinetime::Applications::Screens; @@ -50,12 +51,13 @@ SettingSetDate::SettingSetDate(Pinetime::Controllers::DateTime& dateTimeControll : dateTimeController {dateTimeController}, settingSetDateTime {settingSetDateTime} { lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::text_header); lv_label_set_text_static(title, "Set current date"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::icon); lv_label_set_text_static(icon, Symbols::clock); lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index e5a6be2f9b..d90f45b24a 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -30,12 +30,13 @@ SettingSetTime::SettingSetTime(Pinetime::Controllers::DateTime& dateTimeControll : dateTimeController {dateTimeController}, settingsController {settingsController}, settingSetDateTime {settingSetDateTime} { lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::text_header); lv_label_set_text_static(title, "Set current time"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::icon); lv_label_set_text_static(icon, Symbols::clock); lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); @@ -69,7 +70,7 @@ SettingSetTime::SettingSetTime(Pinetime::Controllers::DateTime& dateTimeControll lv_obj_align(btnSetTime, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); lblSetTime = lv_label_create(btnSetTime, nullptr); lv_label_set_text_static(lblSetTime, "Set"); - lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnSetTime, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_style_local_text_color(lblSetTime, LV_LABEL_PART_MAIN, LV_STATE_DISABLED, LV_COLOR_GRAY); lv_obj_set_event_cb(btnSetTime, SetTimeEventHandler); diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.cpp b/src/displayapp/screens/settings/SettingShakeThreshold.cpp index be67cc9563..f60af3dc11 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.cpp +++ b/src/displayapp/screens/settings/SettingShakeThreshold.cpp @@ -20,6 +20,7 @@ SettingShakeThreshold::SettingShakeThreshold(Controllers::Settings& settingsCont : settingsController {settingsController}, motionController {motionController}, systemTask {systemTask} { lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::text_header); lv_label_set_text_static(title, "Wake Sensitivity"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 0); diff --git a/src/displayapp/screens/settings/SettingSteps.cpp b/src/displayapp/screens/settings/SettingSteps.cpp index b8d5c4055a..41e559855a 100644 --- a/src/displayapp/screens/settings/SettingSteps.cpp +++ b/src/displayapp/screens/settings/SettingSteps.cpp @@ -27,12 +27,13 @@ SettingSteps::SettingSteps(Pinetime::Controllers::Settings& settingsController) lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::text_header); lv_label_set_text_static(title, "Daily steps goal"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::icon); lv_label_set_text_static(icon, Symbols::shoe); lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); @@ -51,7 +52,7 @@ SettingSteps::SettingSteps(Pinetime::Controllers::Settings& settingsController) btnPlus->user_data = this; lv_obj_set_size(btnPlus, btnWidth, btnHeight); lv_obj_align(btnPlus, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - lv_obj_set_style_local_bg_color(btnPlus, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnPlus, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_t* lblPlus = lv_label_create(btnPlus, nullptr); lv_obj_set_style_local_text_font(lblPlus, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text_static(lblPlus, "+"); @@ -62,7 +63,7 @@ SettingSteps::SettingSteps(Pinetime::Controllers::Settings& settingsController) lv_obj_set_size(btnMinus, btnWidth, btnHeight); lv_obj_set_event_cb(btnMinus, event_handler); lv_obj_align(btnMinus, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); - lv_obj_set_style_local_bg_color(btnMinus, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(btnMinus, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_t* lblMinus = lv_label_create(btnMinus, nullptr); lv_obj_set_style_local_text_font(lblMinus, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); lv_label_set_text_static(lblMinus, "-"); diff --git a/src/displayapp/screens/settings/SettingTheme.cpp b/src/displayapp/screens/settings/SettingTheme.cpp new file mode 100644 index 0000000000..d35e5dda36 --- /dev/null +++ b/src/displayapp/screens/settings/SettingTheme.cpp @@ -0,0 +1,97 @@ +#include "displayapp/screens/settings/SettingTheme.h" +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + void ReloadButtonEventHandler(lv_obj_t* obj, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + auto* screen = static_cast(obj->user_data); + screen->OnReloadButtonClicked(); + } + } +} + +SettingTheme::SettingTheme(Pinetime::Applications::DisplayApp* app) : app {app} { + + lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); + + lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); + lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); + lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + + lv_obj_set_pos(container1, 10, 60); + lv_obj_set_width(container1, LV_HOR_RES - 20); + lv_obj_set_height(container1, LV_VER_RES - 50); + lv_cont_set_layout(container1, LV_LAYOUT_PRETTY_TOP); + + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(title, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::text_header); + lv_label_set_text_static(title, "Theme"); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 15); + + lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::icon); + lv_label_set_text_static(icon, Symbols::paintbrush); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + // Status label showing whether built-in or custom theme is used + statusLabel = lv_label_create(container1, nullptr); + lv_label_set_long_mode(statusLabel, LV_LABEL_LONG_BREAK); + lv_obj_set_width(statusLabel, LV_HOR_RES - 40); + lv_label_set_text_static(statusLabel, "Checking..."); + lv_obj_set_style_local_text_color(statusLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + + // Reload button + reloadButton = lv_btn_create(container1, nullptr); + lv_obj_set_width(reloadButton, LV_HOR_RES - 40); + lv_obj_set_height(reloadButton, 50); + lv_obj_set_style_local_radius(reloadButton, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 10); + lv_obj_set_style_local_bg_color(reloadButton, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_MAKE(0x38, 0x38, 0x38)); + lv_obj_set_style_local_bg_opa(reloadButton, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER); + lv_obj_set_style_local_text_color(reloadButton, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_pad_all(reloadButton, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 10); + + lv_obj_t* btnLabel = lv_label_create(reloadButton, nullptr); + lv_label_set_text_static(btnLabel, "Reload Theme"); + lv_label_set_align(btnLabel, LV_LABEL_ALIGN_CENTER); + + reloadButton->user_data = this; + lv_obj_set_event_cb(reloadButton, ReloadButtonEventHandler); + + // Update status to show current theme + UpdateThemeStatus(); +} + +SettingTheme::~SettingTheme() { + lv_obj_clean(lv_scr_act()); +} + +void SettingTheme::UpdateThemeStatus() { + if (statusLabel == nullptr) { + return; + } + + if (lv_pinetime_theme_is_custom_loaded()) { + lv_label_set_text_static(statusLabel, "Custom theme loaded"); + lv_obj_set_style_local_text_color(statusLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + } else { + lv_label_set_text_static(statusLabel, "Using built-in colors"); + lv_obj_set_style_local_text_color(statusLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + } +} + +void SettingTheme::OnReloadButtonClicked() { + // Reload the theme configuration from the filesystem + lv_pinetime_theme_reload_config(); + + // Close this screen - when the user returns, it will be recreated with the new theme applied + app->StartApp(Apps::Settings, DisplayApp::FullRefreshDirections::Up); +} diff --git a/src/displayapp/screens/settings/SettingTheme.h b/src/displayapp/screens/settings/SettingTheme.h new file mode 100644 index 0000000000..1a33bf66f6 --- /dev/null +++ b/src/displayapp/screens/settings/SettingTheme.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "displayapp/screens/Screen.h" + +namespace Pinetime { + + namespace Applications { + namespace Screens { + + class SettingTheme : public Screen { + public: + SettingTheme(Pinetime::Applications::DisplayApp* app); + ~SettingTheme() override; + void OnReloadButtonClicked(); + + private: + Pinetime::Applications::DisplayApp* app; + lv_obj_t* statusLabel; + lv_obj_t* reloadButton; + + void UpdateThemeStatus(); + + static void ReloadButtonCallback(lv_obj_t* obj, lv_event_t event); + }; + } + } +} diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 32ac3ca943..890d8912e2 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -50,6 +50,7 @@ namespace Pinetime { {Symbols::shieldAlt, "Over-the-air", Apps::SettingOTA}, {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, {Symbols::list, "About", Apps::SysInfo}, + {Symbols::paintbrush, "Theme", Apps::SettingTheme}, }}; ScreenList screens; }; diff --git a/src/displayapp/widgets/Counter.cpp b/src/displayapp/widgets/Counter.cpp index b486e3727f..b86c66bbe7 100644 --- a/src/displayapp/widgets/Counter.cpp +++ b/src/displayapp/widgets/Counter.cpp @@ -122,7 +122,7 @@ void Counter::SetValueChangedEventCallback(void* userData, void (*handler)(void* void Counter::Create() { counterContainer = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(counterContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(counterContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); number = lv_label_create(counterContainer, nullptr); lv_obj_set_style_local_text_font(number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &font); @@ -144,7 +144,7 @@ void Counter::Create() { UpdateLabel(); upBtn = lv_btn_create(counterContainer, nullptr); - lv_obj_set_style_local_bg_color(upBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(upBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_size(upBtn, width, btnHeight); lv_obj_align(upBtn, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); upBtn->user_data = this; @@ -156,7 +156,7 @@ void Counter::Create() { lv_obj_align(upLabel, nullptr, LV_ALIGN_CENTER, 0, 0); downBtn = lv_btn_create(counterContainer, nullptr); - lv_obj_set_style_local_bg_color(downBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); + lv_obj_set_style_local_bg_color(downBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::accent); lv_obj_set_size(downBtn, width, btnHeight); lv_obj_align(downBtn, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); downBtn->user_data = this; diff --git a/src/displayapp/widgets/PageIndicator.cpp b/src/displayapp/widgets/PageIndicator.cpp index cee979f22c..a04dd12fb7 100644 --- a/src/displayapp/widgets/PageIndicator.cpp +++ b/src/displayapp/widgets/PageIndicator.cpp @@ -14,7 +14,7 @@ void PageIndicator::Create() { pageIndicatorBase = lv_line_create(lv_scr_act(), nullptr); lv_obj_set_style_local_line_width(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 3); - lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, Colors::bgDark); + lv_obj_set_style_local_line_color(pageIndicatorBase, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, Colors::accent_dark); lv_line_set_points(pageIndicatorBase, pageIndicatorBasePoints, 2); pageIndicator = lv_line_create(lv_scr_act(), nullptr);