From 3cc3f50f7b9364ffac38349238cd6d9aa243dc23 Mon Sep 17 00:00:00 2001 From: Maciej Gibowicz Date: Wed, 22 Nov 2023 09:26:16 +0100 Subject: [PATCH] [BH-1809][BH-1835] Add date format setting Added date format selection between DD/MM and MM/DD. The time setting has been updated. --- harmony_changelog.md | 2 + image/system_a/data/lang/Deutsch.json | 1 + image/system_a/data/lang/English.json | 1 + image/system_a/data/lang/Espanol.json | 1 + image/system_a/data/lang/Francais.json | 1 + image/system_a/data/lang/Polski.json | 1 + .../apps-common/widgets/DateSetSpinner.cpp | 250 ++++++------------ .../apps-common/widgets/DateSetSpinner.hpp | 39 +-- .../apps-common/widgets/TimeSetFmtSpinner.hpp | 12 +- module-utils/time/time/dateCommon.hpp | 24 ++ .../application-bell-settings/CMakeLists.txt | 2 + .../data/BellSettingsStyle.hpp | 7 +- .../models/DateTimeUnitsModel.hpp | 9 +- .../models/DateTimeUnitsModel.cpp | 95 ++++--- .../widgets/DateFormatSetListItem.cpp | 82 ++++++ .../widgets/DateFormatSetListItem.hpp | 36 +++ .../widgets/DateSetListItem.cpp | 24 +- .../widgets/DateSetListItem.hpp | 33 ++- .../widgets/TimeFormatSetListItem.cpp | 4 +- .../widgets/TimeSetListItem.cpp | 16 +- .../widgets/TimeSetListItem.hpp | 6 +- .../HomeScreenLayoutClassicWithDate.cpp | 10 +- .../HomeScreenLayoutVerticalWithDate.cpp | 17 +- 23 files changed, 408 insertions(+), 265 deletions(-) create mode 100644 products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.cpp create mode 100644 products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.hpp diff --git a/harmony_changelog.md b/harmony_changelog.md index 62b868c506632ace2a1b126a39ee6d34f01229bc..afff2a5aef166e531f87f0fc262d24abfa257b9c 100644 --- a/harmony_changelog.md +++ b/harmony_changelog.md @@ -12,11 +12,13 @@ * Added shortcuts instruction to settings * Added brightness fade in functionality * Added labels to Relaxation +* Added date format setting ### Changed / Improved * Optimize the way Relaxation is loading music files * Disabled Address Sanitizer for the Linux simulator * Changed misleading factory reset translations in Polish +* Time setting updated ## [2.2.2 2023-11-14] diff --git a/image/system_a/data/lang/Deutsch.json b/image/system_a/data/lang/Deutsch.json index 8aa842185a4bbe58c88f5edc1b408cd2a488e117..490997d4b10fb283d60072f15bca6ce3c34148f1 100644 --- a/image/system_a/data/lang/Deutsch.json +++ b/image/system_a/data/lang/Deutsch.json @@ -104,6 +104,7 @@ "app_bell_settings_temp_scale": "Temperaturskala", "app_bell_settings_time_units": "Zeit", "app_bell_settings_time_units_time_fmt_top_message": "Zeitformat", + "app_bell_settings_time_units_date_fmt_top_message": "Datumsformat", "app_bell_settings_time_units_time_message": "Zeit", "app_bell_settings_turn_off": "Ausschalten", "app_bell_turn_off_question": "Schalten Sie das Ger\u00e4t aus?", diff --git a/image/system_a/data/lang/English.json b/image/system_a/data/lang/English.json index 36307bb9f530a1499f54a145dba1d28b29b3007b..40b0343199eb4db4a558377f1fb640861d5204a6 100644 --- a/image/system_a/data/lang/English.json +++ b/image/system_a/data/lang/English.json @@ -138,6 +138,7 @@ "app_bell_settings_temp_scale": "Temperature scale", "app_bell_settings_time_units": "Time", "app_bell_settings_time_units_time_fmt_top_message": "Time format", + "app_bell_settings_time_units_date_fmt_top_message": "Date format", "app_bell_settings_time_units_time_message": "Time", "app_bell_settings_turn_off": "Turn off", "app_bell_turn_off_question": "Turn off Mudita Harmony?", diff --git a/image/system_a/data/lang/Espanol.json b/image/system_a/data/lang/Espanol.json index 6dbc9d463d90f74e56c747504a2074293ceb36f3..ed3009251a2afcd68fb4d08896bd804f1c5b3e21 100644 --- a/image/system_a/data/lang/Espanol.json +++ b/image/system_a/data/lang/Espanol.json @@ -103,6 +103,7 @@ "app_bell_settings_temp_scale": "Escala de temperatura", "app_bell_settings_time_units": "Hora", "app_bell_settings_time_units_time_fmt_top_message": "Formato de hora", + "app_bell_settings_time_units_date_fmt_top_message": "Formato de fecha", "app_bell_settings_time_units_time_message": "Hora", "app_bell_settings_turn_off": "Apagar", "app_bell_turn_off_question": "\u00bfApagar Mudita Harmony?", diff --git a/image/system_a/data/lang/Francais.json b/image/system_a/data/lang/Francais.json index e9b65f73acc6fcc8e399a7ab586f400dc0cf74db..53e66a41ce42ae7b89bc43adfbd08ad123e4a5ad 100644 --- a/image/system_a/data/lang/Francais.json +++ b/image/system_a/data/lang/Francais.json @@ -105,6 +105,7 @@ "app_bell_settings_temp_scale": "\u00c9chelle de temp\u00e9rature", "app_bell_settings_time_units": "Temps", "app_bell_settings_time_units_time_fmt_top_message": "Format de l'heure", + "app_bell_settings_time_units_date_fmt_top_message": "Format de la date", "app_bell_settings_time_units_time_message": "Heure", "app_bell_settings_turn_off": "\u00c9teindre", "app_bell_turn_off_question": "\u00c9teindre l'appareil ?", diff --git a/image/system_a/data/lang/Polski.json b/image/system_a/data/lang/Polski.json index 034728087a0ae5646ae47e76ae24e114c74c5566..522063df700d938e54f42621b7d24ea72e88de42 100644 --- a/image/system_a/data/lang/Polski.json +++ b/image/system_a/data/lang/Polski.json @@ -104,6 +104,7 @@ "app_bell_settings_temp_scale": "Skala temperatury", "app_bell_settings_time_units": "Czas", "app_bell_settings_time_units_time_fmt_top_message": "Format czasu", + "app_bell_settings_time_units_date_fmt_top_message": "Format daty", "app_bell_settings_time_units_time_message": "Czas", "app_bell_settings_turn_off": "Wy\u0142\u0105cz", "app_bell_turn_off_question": "Wy\u0142\u0105czy\u0107 Mudita Harmony?", diff --git a/module-apps/apps-common/widgets/DateSetSpinner.cpp b/module-apps/apps-common/widgets/DateSetSpinner.cpp index 42a8870ebfbdab1287ac68f8d01c1041dfb736d8..d59c5682fa13a273304e1043a359fe484e1e4277 100644 --- a/module-apps/apps-common/widgets/DateSetSpinner.cpp +++ b/module-apps/apps-common/widgets/DateSetSpinner.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "DateSetSpinner.hpp" @@ -16,8 +16,9 @@ namespace gui constexpr std::uint8_t step = 1; constexpr std::uint8_t dayMin = 1; constexpr std::uint8_t dayMax = 31; - constexpr auto focusFontName = style::window::font::large; - constexpr auto noFocusFontName = style::window::font::largelight; + constexpr std::uint8_t monthMin = 1; + constexpr std::uint8_t monthMax = 12; + constexpr auto fontName = style::window::font::supersizeme; void setFont(TextFixedSize *elem, const std::string &fontName) { @@ -26,221 +27,124 @@ namespace gui elem->setMinimumWidthToFitText(); elem->setText(elem->getText()); } - - class FocusHelper - { - public: - FocusHelper &year() - { - year_ = focusFontName; - return *this; - } - - FocusHelper &month() - { - month_ = focusFontName; - return *this; - } - - FocusHelper &day() - { - day_ = focusFontName; - return *this; - } - - void focus(U8IntegerSpinnerFixed *elementDay, - U8IntegerSpinnerFixed *elementMonth, - U16IntegerSpinnerFixed *elementYear) - { - setFont(elementDay, day_); - setFont(elementMonth, month_); - setFont(elementYear, year_); - } - - private: - std::string year_{noFocusFontName}; - std::string month_{noFocusFontName}; - std::string day_{noFocusFontName}; - }; } // namespace - DateSetSpinner::DateSetSpinner(Item *parent, TextFixedSize *title, Length x, Length y, Length w, Length h) - : HBox(parent, x, y, w, h), title{title} + DateSetSpinner::DateSetSpinner( + Item *parent, Type type, TextFixedSize *title, Length x, Length y, Length w, Length h) + : HBox(parent, x, y, w, h), type{type}, title{title} { - constexpr std::uint8_t monthMin = 1; - constexpr std::uint8_t monthMax = 12; - setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center)); setEdges(RectangleEdge::None); - attachDateField( - year, U16IntegerSpinnerFixed::range{utils::time::Locale::min_years, utils::time::Locale::max_years, step}); - attachSlash(firstSlash); - attachDateField(month, U8IntegerSpinnerFixed::range{monthMin, monthMax, step}); - attachSlash(secondSlash); - attachDateField(day, U8IntegerSpinnerFixed::range{dayMin, dayMax, step}); - - month->onValueChanged = [this](auto) { correctDayOfMonth(); }; - year->onValueChanged = [this](auto) { correctDayOfMonth(); }; + switch (type) { + case Type::year: + attachDateField( + year, + U16IntegerSpinnerFixed::range{utils::time::Locale::min_years, utils::time::Locale::max_years, step}); + year->onValueChanged = [this](auto) { updateDate(); }; + setFocusItem(year); + break; + case Type::month: + attachDateField(dayMonth, U8IntegerSpinnerFixed::range{monthMin, monthMax, step}); + dayMonth->onValueChanged = [this](auto) { updateDate(); }; + setFocusItem(dayMonth); + break; + case Type::day: + attachDateField(dayMonth, U8IntegerSpinnerFixed::range{dayMin, dayMax, step}); + dayMonth->onValueChanged = [this](auto) { updateDate(); }; + setFocusItem(dayMonth); + break; + } resizeItems(); - - focusChangedCallback = [&](Item &) { - if (lastFocus != nullptr) { - updateFocus(lastFocus); - } - return true; - }; - - updateFocus(year); + applySizeRestrictions(); } - date::year_month_day DateSetSpinner::getDate() + date::year_month_day DateSetSpinner::getDate() const { - return date::year(year->get_value()) / date::month(month->get_value()) / date::day(day->get_value()); + return date; } void DateSetSpinner::setDate(const date::year_month_day date) { - day->set_value(static_cast(date.day())); - month->set_value(static_cast(date.month())); - year->set_value(static_cast(date.year())); + this->date = date; + switch (type) { + case Type::year: + year->set_value(static_cast(date.year())); + break; + case Type::month: + dayMonth->set_value(static_cast(date.month())); + break; + case Type::day: + const auto lastDayInMonth = + static_cast((date::year(date.year()) / date::month(date.month()) / date::last).day()); + const auto day = static_cast(date.day()); + dayMonth->set_range({dayMin, static_cast(lastDayInMonth), step}); + dayMonth->set_value(std::min(day, lastDayInMonth)); + break; + } applySizeRestrictions(); } + void DateSetSpinner::updateDate() + { + switch (type) { + case Type::year: + date = date::year(year->get_value()) / date::month(date.month()) / date::day(date.day()); + break; + case Type::month: + date = date::year(date.year()) / date::month(dayMonth->get_value()) / date::day(date.day()); + break; + case Type::day: + date = date::year(date.year()) / date::month(date.month()) / date::day(dayMonth->get_value()); + break; + } + } + void DateSetSpinner::applySizeRestrictions() { - day->setMinimumWidthToFitText(); - firstSlash->setMinimumWidthToFitText(); - month->setMinimumWidthToFitText(); - secondSlash->setMinimumWidthToFitText(); - year->setMinimumWidthToFitText(); + if (year != nullptr) { + year->setMinimumWidthToFitText(); + } + if (dayMonth != nullptr) { + dayMonth->setMinimumWidthToFitText(); + } - setMinimumSize(getWidgetMinimumAreaWidth(), getFontHeight(noFocusFontName)); + setMinimumSize(getWidgetMinimumAreaWidth(), getFontHeight(fontName)); setMaximumWidth(widgetMaximumArea.w); HBox::informContentChanged(); } - std::uint32_t DateSetSpinner::getWidgetMinimumAreaWidth() + std::uint32_t DateSetSpinner::getWidgetMinimumAreaWidth() const { - return day->widgetMinimumArea.w + firstSlash->widgetMinimumArea.w + month->widgetMinimumArea.w + - secondSlash->widgetMinimumArea.w + year->widgetMinimumArea.w; + return (type == Type::year) ? year->widgetMinimumArea.w : dayMonth->widgetMinimumArea.w; + } + + std::uint16_t DateSetSpinner::getFontHeight(const std::string &fontName) const + { + const auto font = FontManager::getInstance().getFont(fontName); + return font->info.line_height; } template void DateSetSpinner::attachDateField(Spinner *&field, typename Spinner::range &&range) { field = new Spinner(std::move(range), Boundaries::Continuous); - setFont(field, noFocusFontName); + setFont(field, fontName); field->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center)); field->setEdges(RectangleEdge::None); - field->setPenFocusWidth(4); + field->setPenFocusWidth(0); field->set_value(0); addWidget(field); } - void DateSetSpinner::attachSlash(gui::Label *&slash) - { - slash = new gui::Label(this, 0, 0, 0, 0); - setFont(slash, noFocusFontName); - slash->setEdges(gui::RectangleEdge::None); - slash->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center)); - slash->setEdges(RectangleEdge::None); - slash->setText("/"); - slash->activeItem = false; - } - - std::uint16_t DateSetSpinner::getFontHeight(const std::string &fontName) const - { - const RawFont *font = FontManager::getInstance().getFont(fontName); - return font->info.line_height; - } - bool DateSetSpinner::onInput(const InputEvent &inputEvent) { if (auto ret = this->focusItem->onInput(inputEvent)) { applySizeRestrictions(); return ret; } - - if (inputEvent.isShortRelease()) { - switch (inputEvent.getKeyCode()) { - case KeyCode::KEY_ENTER: - return handleEnterKey(); - case KeyCode::KEY_RF: - return handleRightFunctionKey(); - default: - break; - } - } - return false; - } - - void DateSetSpinner::correctDayOfMonth() - { - const auto dayCountInMonth = - static_cast((date::year(year->get_value()) / date::month(month->get_value()) / date::last).day()); - - if (day->get_value() > dayCountInMonth) { - day->set_value(dayCountInMonth); - } - - const auto currentValue = day->get_value(); - day->set_range({dayMin, static_cast(dayCountInMonth), step}); - day->set_value(currentValue); - } - - bool DateSetSpinner::handleEnterKey() - { - if (focusItem == year) { - updateFocus(month); - return true; - } - if (focusItem == month) { - updateFocus(day); - return true; - } - return false; - } - - bool DateSetSpinner::handleRightFunctionKey() - { - if (focusItem == month) { - updateFocus(year); - return true; - } - if (focusItem == day) { - updateFocus(month); - return true; - } return false; } - - void DateSetSpinner::updateFocus(Item *newFocus) - { - auto set_title = [this](std::string text) { - if (title != nullptr) { - title->setRichText(text); - } - }; - - setFocusItem(newFocus); - lastFocus = newFocus; - - if (month->focus) { - set_title(utils::translate("app_settings_title_month")); - FocusHelper{}.month().focus(day, month, year); - } - else if (day->focus) { - set_title(utils::translate("app_settings_title_day")); - FocusHelper{}.day().focus(day, month, year); - } - else if (year->focus) { - set_title(utils::translate("app_settings_title_year")); - FocusHelper{}.year().focus(day, month, year); - } - - applySizeRestrictions(); - } } /* namespace gui */ diff --git a/module-apps/apps-common/widgets/DateSetSpinner.hpp b/module-apps/apps-common/widgets/DateSetSpinner.hpp index 6929aebd2d9bf25022d50e13209e2db965cc1890..8378eaafecde4b4b58a766f53f7defdcee988073 100644 --- a/module-apps/apps-common/widgets/DateSetSpinner.hpp +++ b/module-apps/apps-common/widgets/DateSetSpinner.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -15,31 +15,32 @@ namespace gui class DateSetSpinner : public HBox { public: - DateSetSpinner(Item *parent, TextFixedSize *titleBox, Length x, Length y, Length w, Length h); + enum class Type + { + year, + month, + day + }; - date::year_month_day getDate(); + DateSetSpinner(Item *parent, Type type, TextFixedSize *titleBox, Length x, Length y, Length w, Length h); + + date::year_month_day getDate() const; void setDate(date::year_month_day date); private: void applySizeRestrictions(); - std::uint32_t getWidgetMinimumAreaWidth(); + std::uint32_t getWidgetMinimumAreaWidth() const; + std::uint16_t getFontHeight(const std::string &fontName) const; + template void attachDateField(Spinner *&field, typename Spinner::range &&range); - void attachSlash(gui::Label *&slash); - std::uint16_t getFontHeight(const std::string &fontName) const; - void updateFocus(Item *newFocus); + void updateDate(); bool onInput(const InputEvent &inputEvent) override; - void correctDayOfMonth(); - bool handleEnterKey(); - bool handleRightFunctionKey(); - - TextFixedSize *title = nullptr; - U8IntegerSpinnerFixed *day = nullptr; - Label *firstSlash = nullptr; - U8IntegerSpinnerFixed *month = nullptr; - Label *secondSlash = nullptr; - U16IntegerSpinnerFixed *year = nullptr; - - Item *lastFocus = nullptr; + + Type type; + date::year_month_day date; + TextFixedSize *title{nullptr}; + U16IntegerSpinnerFixed *year{nullptr}; + U8IntegerSpinnerFixed *dayMonth{nullptr}; }; } /* namespace gui */ diff --git a/module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp b/module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp index b2fada4f3df771e1097b3c193f6afdfac81ed15a..7910423f2a376cc2074d72c205796243672783c9 100644 --- a/module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp +++ b/module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp @@ -83,13 +83,13 @@ namespace gui auto handleRightFunctionKey() -> bool; void handleContentChanged() override; - TimeSetSpinner *timeSetSpinner = nullptr; - StringSpinner *fmt = nullptr; - EditMode editMode = EditMode::Edit; - std::string focusFontName = style::window::font::supersizeme; - std::string noFocusFontName = style::window::font::supersizemelight; + TimeSetSpinner *timeSetSpinner{nullptr}; + StringSpinner *fmt{nullptr}; + EditMode editMode{EditMode::Edit}; + std::string focusFontName{style::window::font::supersizeme}; + std::string noFocusFontName{style::window::font::supersizemelight}; - utils::time::Locale::TimeFormat timeFormat = utils::time::Locale::TimeFormat::FormatTime12H; + utils::time::Locale::TimeFormat timeFormat{utils::time::Locale::TimeFormat::FormatTime12H}; }; } // namespace gui diff --git a/module-utils/time/time/dateCommon.hpp b/module-utils/time/time/dateCommon.hpp index 27a029d3d69e3dd891e28255bf2c00d1aec87266..140bc1ec96a36cae5e6ca363659864895f356cea 100644 --- a/module-utils/time/time/dateCommon.hpp +++ b/module-utils/time/time/dateCommon.hpp @@ -375,6 +375,30 @@ inline TimePoint nextTimePointFromHHMM(std::chrono::hours hours, std::chrono::mi return GetFollowingDayTime(nextTime, from); } +/// @brief Time conversion to date in DDMM format +/// @param time - a pointer to a time structure +/// @return date string in DD/MM format +inline std::string GetDateInDDMMFormat(const struct tm *time) +{ + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << time->tm_mday; + ss << '/'; + ss << std::setfill('0') << std::setw(2) << (time->tm_mon + 1); + return ss.str(); +} + +/// @brief Time conversion to date in MMDD format +/// @param time - a pointer to a time structure +/// @return date string in MM/DD format +inline std::string GetDateInMMDDFormat(const struct tm *time) +{ + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << (time->tm_mon + 1); + ss << '/'; + ss << std::setfill('0') << std::setw(2) << time->tm_mday; + return ss.str(); +} + inline std::string createUID() { constexpr auto bufferSize = 16; diff --git a/products/BellHybrid/apps/application-bell-settings/CMakeLists.txt b/products/BellHybrid/apps/application-bell-settings/CMakeLists.txt index c8f00074eadf7076f8ef99cd7306a94f4fb5b005..c609c13c928919e9f8e8c9f94fe7eb741ee579ac 100644 --- a/products/BellHybrid/apps/application-bell-settings/CMakeLists.txt +++ b/products/BellHybrid/apps/application-bell-settings/CMakeLists.txt @@ -50,6 +50,7 @@ target_sources(application-bell-settings widgets/TemperatureUnitListItem.cpp widgets/TimeFormatSetListItem.cpp + widgets/DateFormatSetListItem.cpp widgets/DateSetListItem.cpp widgets/TimeSetListItem.cpp widgets/AboutYourBellListItem.cpp @@ -92,6 +93,7 @@ target_sources(application-bell-settings widgets/TemperatureUnitListItem.hpp widgets/TimeFormatSetListItem.hpp + widgets/DateFormatSetListItem.hpp widgets/TimeSetListItem.hpp widgets/AboutYourBellListItem.hpp widgets/DialogYesNo.hpp diff --git a/products/BellHybrid/apps/application-bell-settings/data/BellSettingsStyle.hpp b/products/BellHybrid/apps/application-bell-settings/data/BellSettingsStyle.hpp index 2d03492b46b1f34d2b53732a1401f6224e564894..9472049c0a5de99a850ea980aab0dd7cd1961c1d 100644 --- a/products/BellHybrid/apps/application-bell-settings/data/BellSettingsStyle.hpp +++ b/products/BellHybrid/apps/application-bell-settings/data/BellSettingsStyle.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -22,6 +22,11 @@ namespace gui inline constexpr auto font = style::window::font::supersizeme; } // namespace time_fmt_set_list_item + namespace date_fmt_set_list_item + { + inline constexpr auto font = style::window::font::supersizeme; + } // namespace date_fmt_set_list_item + namespace top_text { inline constexpr auto font = style::window::font::largelight; diff --git a/products/BellHybrid/apps/application-bell-settings/include/application-bell-settings/models/DateTimeUnitsModel.hpp b/products/BellHybrid/apps/application-bell-settings/include/application-bell-settings/models/DateTimeUnitsModel.hpp index 10dea65798c1e94c8bd0e48159899859872fab7d..f8260798c2b4b0742108fd66d26de2461e85ec73 100644 --- a/products/BellHybrid/apps/application-bell-settings/include/application-bell-settings/models/DateTimeUnitsModel.hpp +++ b/products/BellHybrid/apps/application-bell-settings/include/application-bell-settings/models/DateTimeUnitsModel.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -13,6 +13,7 @@ namespace gui class DateSetListItem; class TimeSetListItem; class TimeFormatSetListItem; + class DateFormatSetListItem; class TemperatureUnitListItem; } // namespace gui @@ -38,13 +39,17 @@ namespace app::bell_settings protected: app::ApplicationCommon *application{}; - gui::DateSetListItem *dateSetListItem{}; + gui::DateSetListItem *yearSetListItem{}; + gui::DateSetListItem *monthSetListItem{}; + gui::DateSetListItem *daySetListItem{}; gui::TimeSetListItem *timeSetListItem{}; + gui::DateFormatSetListItem *dateFmtSetListItem{}; gui::TimeFormatSetListItem *timeFmtSetListItem{}; gui::TemperatureUnitListItem *temperatureUnitListItem{}; void sendRtcUpdateTimeMessage(time_t newTime); void sendTimeFmtUpdateMessage(utils::time::Locale::TimeFormat newFmt); + void sendDateFmtUpdateMessage(utils::time::Locale::DateFormat newFmt); }; class DateTimeUnitsModelFactoryResetValues : public DateTimeUnitsModel diff --git a/products/BellHybrid/apps/application-bell-settings/models/DateTimeUnitsModel.cpp b/products/BellHybrid/apps/application-bell-settings/models/DateTimeUnitsModel.cpp index 52fcd7fa646e033464ec97d7ed4aa285d03a0521..491cba55e947e52632c607b23a0c165c1ca84cf3 100644 --- a/products/BellHybrid/apps/application-bell-settings/models/DateTimeUnitsModel.cpp +++ b/products/BellHybrid/apps/application-bell-settings/models/DateTimeUnitsModel.cpp @@ -4,6 +4,7 @@ #include "models/DateTimeUnitsModel.hpp" #include "widgets/DateSetListItem.hpp" #include "widgets/TimeFormatSetListItem.hpp" +#include "widgets/DateFormatSetListItem.hpp" #include "widgets/TimeSetListItem.hpp" #include "widgets/TemperatureUnitListItem.hpp" #include "ProductConfig.hpp" @@ -45,26 +46,50 @@ namespace app::bell_settings void DateTimeUnitsModel::createData() { - dateSetListItem = new gui::DateSetListItem(); - internalData.push_back(dateSetListItem); + yearSetListItem = new gui::YearSetListItem(utils::translate("app_settings_title_year")); + internalData.push_back(yearSetListItem); - timeFmtSetListItem = new gui::TimeFormatSetListItem( - 0, 0, 0, 0, utils::translate("app_bell_settings_time_units_time_fmt_top_message")); - internalData.push_back(timeFmtSetListItem); + monthSetListItem = new gui::MonthSetListItem(utils::translate("app_settings_title_month")); + internalData.push_back(monthSetListItem); + + daySetListItem = new gui::DaySetListItem(utils::translate("app_settings_title_day")); + internalData.push_back(daySetListItem); + + dateFmtSetListItem = new gui::DateFormatSetListItem( + 0, 0, 0, 0, utils::translate("app_bell_settings_time_units_date_fmt_top_message")); + internalData.push_back(dateFmtSetListItem); timeSetListItem = new gui::TimeSetListItem(0U, 0U, 0, 0, utils::translate("app_bell_settings_time_units_time_message")); internalData.push_back(timeSetListItem); - timeFmtSetListItem->onNextCallback = [this](gui::Item &) { - timeSetListItem->timeSetFmtSpinner->setTimeFormat(timeFmtSetListItem->getTimeFmt()); - }; + timeFmtSetListItem = new gui::TimeFormatSetListItem( + 0, 0, 0, 0, utils::translate("app_bell_settings_time_units_time_fmt_top_message")); + internalData.push_back(timeFmtSetListItem); #if CONFIG_ENABLE_TEMP == 1 temperatureUnitListItem = new gui::TemperatureUnitListItem(utils::translate("app_bell_settings_temp_scale")); internalData.push_back(temperatureUnitListItem); #endif + yearSetListItem->onNextCallback = [this](gui::Item &) { + const auto date = yearSetListItem->dateSetSpinner->getDate(); + monthSetListItem->dateSetSpinner->setDate(date); + daySetListItem->dateSetSpinner->setDate(date); + }; + + monthSetListItem->onNextCallback = [this](gui::Item &) { + const auto date = monthSetListItem->dateSetSpinner->getDate(); + daySetListItem->dateSetSpinner->setDate(date); + yearSetListItem->dateSetSpinner->setDate(date); + }; + + daySetListItem->onNextCallback = [this](gui::Item &) { + const auto date = daySetListItem->dateSetSpinner->getDate(); + yearSetListItem->dateSetSpinner->setDate(date); + monthSetListItem->dateSetSpinner->setDate(date); + }; + for (auto item : internalData) { item->deleteByList = false; } @@ -77,38 +102,42 @@ namespace app::bell_settings void DateTimeUnitsModel::saveData() { - const auto date = dateSetListItem->dateSetSpinner->getDate(); + const auto date = daySetListItem->dateSetSpinner->getDate(); const auto year = date.year().operator int(); const auto month = static_cast(date.month().operator unsigned int()); const auto day = static_cast(date.day().operator unsigned int()); - const auto hour = timeSetListItem->timeSetFmtSpinner->getHour24Format(); - const auto minute = timeSetListItem->timeSetFmtSpinner->getMinute(); - const auto fmt = timeFmtSetListItem->getTimeFmt(); + const auto hour = timeSetListItem->timeSetSpinner->getHour(); + const auto minute = timeSetListItem->timeSetSpinner->getMinute(); + const auto timeFormat = timeFmtSetListItem->getTimeFmt(); + const auto dateFormat = dateFmtSetListItem->getDateFmt(); - const auto newTime = GetAsUTCTime(year, month, day, hour.count(), minute); + const auto newTime = GetAsUTCTime(year, month, day, hour, minute); - LOG_DEBUG("Setting a new date/time: %d/%d/%d %d:%d %s", + LOG_DEBUG("Setting a new date/time: %02d/%02d/%d (%s) %d:%02d (%s)", + (dateFormat == utils::time::Locale::DateFormat::DD_MM_YYYY) ? day : month, + (dateFormat == utils::time::Locale::DateFormat::DD_MM_YYYY) ? month : day, year, - month, - day, - static_cast(hour.count()), + utils::time::Locale::get_date_format(dateFormat).data(), + hour, minute, - utils::time::Locale::get_time_format(fmt).data()); + utils::time::Locale::get_time_format(timeFormat).data()); sendRtcUpdateTimeMessage(newTime); - sendTimeFmtUpdateMessage(fmt); + sendTimeFmtUpdateMessage(timeFormat); + sendDateFmtUpdateMessage(dateFormat); } void DateTimeUnitsModel::loadData() { const auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); const auto timeFormat = stm::api::timeFormat(); - timeSetListItem->timeSetFmtSpinner->setTimeFormat(timeFormat); - timeSetListItem->timeSetFmtSpinner->setTime(now); - dateSetListItem->dateSetSpinner->setDate( + const auto dateFormat = stm::api::dateFormat(); + timeSetListItem->timeSetSpinner->setTime(now); + yearSetListItem->dateSetSpinner->setDate( date::year_month_day{date::floor(std::chrono::system_clock::now())}); timeFmtSetListItem->setTimeFmt(timeFormat); + dateFmtSetListItem->setDateFmt(dateFormat); } auto DateTimeUnitsModel::requestRecords(uint32_t offset, uint32_t limit) -> void @@ -129,6 +158,12 @@ namespace app::bell_settings application->bus.sendUnicast(std::move(msg), service::name::service_time); } + void DateTimeUnitsModel::sendDateFmtUpdateMessage(utils::time::Locale::DateFormat newFmt) + { + auto msg = std::make_shared(newFmt); + application->bus.sendUnicast(std::move(msg), service::name::service_time); + } + auto DateTimeUnitsModel::getTemperatureUnit() const -> utils::temperature::Temperature::Unit { #if CONFIG_ENABLE_TEMP == 1 @@ -156,13 +191,13 @@ namespace app::bell_settings /// Default date/time after factory reset: 2023/01/01 12:00PM const auto factoryResetDate = 2023_y / jan / 1_d; - const auto factoryRestTimeFmt = utils::time::Locale::TimeFormat::FormatTime12H; - - dateSetListItem->dateSetSpinner->setDate(factoryResetDate); - timeSetListItem->timeSetFmtSpinner->setTimeFormat(factoryRestTimeFmt); - timeSetListItem->timeSetFmtSpinner->setHour(12); - timeSetListItem->timeSetFmtSpinner->setMinute(0); - timeSetListItem->timeSetFmtSpinner->set12HPeriod(gui::TimeSetFmtSpinner::Period::PM); - timeFmtSetListItem->setTimeFmt(factoryRestTimeFmt); + const auto factoryResetTimeFmt = utils::time::Locale::TimeFormat::FormatTime24H; + const auto factoryResetDateFmt = utils::time::Locale::DateFormat::DD_MM_YYYY; + + yearSetListItem->dateSetSpinner->setDate(factoryResetDate); + timeSetListItem->timeSetSpinner->setHour(12); + timeSetListItem->timeSetSpinner->setMinute(0); + timeFmtSetListItem->setTimeFmt(factoryResetTimeFmt); + dateFmtSetListItem->setDateFmt(factoryResetDateFmt); } } // namespace app::bell_settings diff --git a/products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.cpp b/products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed083f14897df76b920e07a117af1d347930af36 --- /dev/null +++ b/products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.cpp @@ -0,0 +1,82 @@ +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "DateFormatSetListItem.hpp" +#include "BellSettingsStyle.hpp" + +#include +#include +#include + +#include + +namespace +{ + constexpr auto fmtSpinner_DD_MM = "DD / MM"; + constexpr auto fmtSpinner_MM_DD = "MM / DD"; +} // namespace + +namespace gui +{ + DateFormatSetListItem::DateFormatSetListItem( + Length x, Length y, Length w, Length h, const UTF8 &topDesc, const UTF8 &botDesc) + { + setupTopTextBox(topDesc); + setMinimumSize(style::sidelistview::list_item::w, style::sidelistview::list_item::h); + setEdges(RectangleEdge::None); + setFocusItem(body); + + dateFormat = new StringSpinner({fmtSpinner_DD_MM, fmtSpinner_MM_DD}, Boundaries::Fixed); + dateFormat->setMaximumSize(style::bell_base_layout::w, style::bell_base_layout::center_layout_h); + dateFormat->setFont(bell_settings_style::date_fmt_set_list_item::font); + dateFormat->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center)); + dateFormat->setFocusEdges(RectangleEdge::None); + dateFormat->onValueChanged = [this](const auto &) { + body->setMinMaxArrowsVisibility(dateFormat->is_min(), dateFormat->is_max()); + }; + + body->getCenterBox()->addWidget(dateFormat); + setupBottomTextBox(botDesc); + dimensionChangedCallback = [&](Item &, const BoundingBox &newDim) -> bool { + body->setArea({0, 0, newDim.w, newDim.h}); + return true; + }; + + focusChangedCallback = [&](Item &) { + setFocusItem(focus ? body : nullptr); + if (focus) { + setFocusItem(body); + } + else { + setFocusItem(nullptr); + if (onNextCallback) { + onNextCallback(*this); + } + } + return true; + }; + + inputCallback = [this](Item &, const InputEvent &inputEvent) -> bool { + const auto ret = body->onInput(inputEvent); + return ret; + }; + } + + auto DateFormatSetListItem::getDateFmt() const noexcept -> utils::time::Locale::DateFormat + { + return (dateFormat->value() == fmtSpinner_DD_MM) ? utils::time::Locale::DateFormat::DD_MM_YYYY + : utils::time::Locale::DateFormat::MM_DD_YYYY; + } + + auto DateFormatSetListItem::setDateFmt(utils::time::Locale::DateFormat fmt) noexcept -> void + { + using namespace utils::time; + if (fmt == Locale::DateFormat::MM_DD_YYYY) { + dateFormat->set_value(fmtSpinner_MM_DD); + } + else { + dateFormat->set_value(fmtSpinner_DD_MM); + } + body->setMinMaxArrowsVisibility(dateFormat->is_min(), dateFormat->is_max()); + } +} // namespace gui diff --git a/products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.hpp b/products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.hpp new file mode 100644 index 0000000000000000000000000000000000000000..01b7c9548bd64eb72a28db8dbf0f07f7629d1f68 --- /dev/null +++ b/products/BellHybrid/apps/application-bell-settings/widgets/DateFormatSetListItem.hpp @@ -0,0 +1,36 @@ +// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include