From a6173976722df15dfc4db3cd0581786e3b5fb747 Mon Sep 17 00:00:00 2001 From: KacperLewandowski Date: Fri, 27 Nov 2020 20:11:00 +0100 Subject: [PATCH] [EGD-4788] Add custom repeat window for the alarm application When choosing alarm repeat option now it is possible to choose specific days of the week and their combinations. --- changelog.md | 1 + image/assets/lang/English.json | 7 ++ .../ApplicationAlarmClock.cpp | 9 ++ .../application-alarm-clock/CMakeLists.txt | 5 + .../data/AlarmsData.cpp | 47 ++++++++ .../data/AlarmsData.hpp | 27 ++++- .../models/CustomRepeatModel.cpp | 75 +++++++++++++ .../models/CustomRepeatModel.hpp | 43 ++++++++ .../models/NewEditAlarmModel.cpp | 12 ++- .../models/NewEditAlarmModel.hpp | 3 + .../AlarmClockEditWindowPresenter.cpp | 12 +++ .../AlarmClockEditWindowPresenter.hpp | 4 + .../presenter/CustomRepeatWindowPresenter.cpp | 34 ++++++ .../presenter/CustomRepeatWindowPresenter.hpp | 43 ++++++++ .../widgets/AlarmClockStyle.hpp | 8 ++ .../widgets/AlarmInternalListItem.hpp | 1 + .../widgets/AlarmItem.cpp | 2 +- .../widgets/AlarmOptionsItem.cpp | 59 ++++++++++- .../widgets/AlarmOptionsItem.hpp | 1 + .../widgets/CustomCheckBoxWithLabel.cpp | 100 ++++++++++++++++++ .../widgets/CustomCheckBoxWithLabel.hpp | 33 ++++++ .../windows/CustomRepeatWindow.cpp | 65 ++++++++++++ .../windows/CustomRepeatWindow.hpp | 30 ++++++ .../windows/NewEditAlarmWindow.cpp | 8 ++ 24 files changed, 622 insertions(+), 7 deletions(-) create mode 100644 module-apps/application-alarm-clock/data/AlarmsData.cpp create mode 100644 module-apps/application-alarm-clock/models/CustomRepeatModel.cpp create mode 100644 module-apps/application-alarm-clock/models/CustomRepeatModel.hpp create mode 100644 module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.cpp create mode 100644 module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.hpp create mode 100644 module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.cpp create mode 100644 module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.hpp create mode 100644 module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp create mode 100644 module-apps/application-alarm-clock/windows/CustomRepeatWindow.hpp diff --git a/changelog.md b/changelog.md index 9d40e64ef332417bbb0326253fc07fa34dc0107f..3e3190d3bde71279bb7818f423a4976bf25a5bc7 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ * `[PowerManagement]` Critial battery level notification to SystemManager. * `[Bluetooth]` Add settings storage to bluetooth related items * Add Bluetooth virtual audio device. +* Add custom repeat window for the alarm application ## [0.51.1 2020-12-18] diff --git a/image/assets/lang/English.json b/image/assets/lang/English.json index 8dd4c5e59833c7bb5f59866b901deca21cda6706..0425ed96382707cf0aa5176bef961c0836554359 100644 --- a/image/assets/lang/English.json +++ b/image/assets/lang/English.json @@ -35,6 +35,13 @@ "common_fr": "FR", "common_sa": "SA", "common_su": "SU", + "common_mon": "Mon", + "common_tue": "Tue", + "common_wed": "Wed", + "common_thu": "Thu", + "common_fri": "Fri", + "common_sat": "Sat", + "common_sun": "Sun", "common_monday": "Monday", "common_tuesday": "Tuesday", "common_wednesday": "Wednesday", diff --git a/module-apps/application-alarm-clock/ApplicationAlarmClock.cpp b/module-apps/application-alarm-clock/ApplicationAlarmClock.cpp index 89672da55be3980ce17d33331bb027e66758bc2b..16d7f1144efceb044dec5a5f3ee69a093c99adf9 100644 --- a/module-apps/application-alarm-clock/ApplicationAlarmClock.cpp +++ b/module-apps/application-alarm-clock/ApplicationAlarmClock.cpp @@ -4,8 +4,10 @@ #include "ApplicationAlarmClock.hpp" #include "application-alarm-clock/windows/AlarmClockMainWindow.hpp" #include "application-alarm-clock/windows/NewEditAlarmWindow.hpp" +#include "application-alarm-clock/windows/CustomRepeatWindow.hpp" #include "application-alarm-clock/widgets/AlarmClockStyle.hpp" #include "application-alarm-clock/presenter/AlarmClockMainWindowPresenter.hpp" +#include "application-alarm-clock/presenter/CustomRepeatWindowPresenter.hpp" #include "windows/Dialog.hpp" #include "windows/AppWindow.hpp" #include "windows/OptionWindow.hpp" @@ -100,6 +102,13 @@ namespace app auto presenter = std::make_unique(alarmsProvider); return std::make_unique(app, std::move(presenter)); }); + windowsFactory.attach( + style::alarmClock::window::name::customRepeat, [](Application *app, const std::string &name) { + auto alarmsRepository = std::make_unique(app); + auto alarmsProvider = std::make_shared(app, std::move(alarmsRepository)); + auto presenter = std::make_unique(alarmsProvider); + return std::make_unique(app, std::move(presenter)); + }); windowsFactory.attach( utils::localize.get("app_alarm_clock_options_title"), [](Application *app, const std::string &name) { return std::make_unique(app, name); }); diff --git a/module-apps/application-alarm-clock/CMakeLists.txt b/module-apps/application-alarm-clock/CMakeLists.txt index 87d1a4344d60aed9e8efd2db748fe59f1a2e2d2e..905cc664b858e69bd1bb80ca0404a7a7865cfd89 100644 --- a/module-apps/application-alarm-clock/CMakeLists.txt +++ b/module-apps/application-alarm-clock/CMakeLists.txt @@ -5,14 +5,19 @@ target_sources( ${PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/windows/AlarmClockMainWindow.cpp" "${CMAKE_CURRENT_LIST_DIR}/windows/AlarmClockOptions.cpp" "${CMAKE_CURRENT_LIST_DIR}/windows/NewEditAlarmWindow.cpp" + "${CMAKE_CURRENT_LIST_DIR}/windows/CustomRepeatWindow.cpp" "${CMAKE_CURRENT_LIST_DIR}/models/AlarmsModel.cpp" "${CMAKE_CURRENT_LIST_DIR}/models/AlarmsRepository.cpp" "${CMAKE_CURRENT_LIST_DIR}/models/NewEditAlarmModel.cpp" + "${CMAKE_CURRENT_LIST_DIR}/models/CustomRepeatModel.cpp" "${CMAKE_CURRENT_LIST_DIR}/widgets/AlarmItem.cpp" "${CMAKE_CURRENT_LIST_DIR}/widgets/AlarmTimeItem.cpp" "${CMAKE_CURRENT_LIST_DIR}/widgets/AlarmOptionsItem.cpp" + "${CMAKE_CURRENT_LIST_DIR}/widgets/CustomCheckBoxWithLabel.cpp" "${CMAKE_CURRENT_LIST_DIR}/presenter/AlarmClockMainWindowPresenter.cpp" "${CMAKE_CURRENT_LIST_DIR}/presenter/AlarmClockEditWindowPresenter.cpp" + "${CMAKE_CURRENT_LIST_DIR}/presenter/CustomRepeatWindowPresenter.cpp" + "${CMAKE_CURRENT_LIST_DIR}/data/AlarmsData.cpp" PUBLIC "${CMAKE_CURRENT_LIST_DIR}/ApplicationAlarmClock.hpp" "${CMAKE_CURRENT_LIST_DIR}/widgets/AlarmClockStyle.hpp" diff --git a/module-apps/application-alarm-clock/data/AlarmsData.cpp b/module-apps/application-alarm-clock/data/AlarmsData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a08744bc25960bfbfa3c9aa84df66ebfa11b9572 --- /dev/null +++ b/module-apps/application-alarm-clock/data/AlarmsData.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "AlarmsData.hpp" + +static const std::map weekDaysAbbreviation = {{WeekDayIso::Monday, "common_mon"}, + {WeekDayIso::Tuesday, "common_tue"}, + {WeekDayIso::Wednesday, "common_wed"}, + {WeekDayIso::Thursday, "common_thu"}, + {WeekDayIso::Friday, "common_fri"}, + {WeekDayIso::Saturday, "common_sat"}, + {WeekDayIso::Sunday, "common_sun"}}; + +CustomRepeatValueParser::CustomRepeatValueParser(uint32_t repeatValue) +{ + OptionParser parser; + weekDayData = parser.setWeekDayOptions(repeatValue, std::make_unique()); +} + +std::string CustomRepeatValueParser::getWeekDaysText() const +{ + std::string weekDaysText; + for (auto const &[key, val] : weekDaysAbbreviation) { + if (weekDayData->getData(static_cast(key))) { + weekDaysText += utils::localize.get(val) + ", "; + } + } + if (!weekDaysText.empty()) { + weekDaysText.erase(weekDaysText.end() - 2); + } + return weekDaysText; +} + +bool CustomRepeatValueParser::isCustomValueWeekDays() const +{ + return weekDayData->getData(static_cast(WeekDayIso::Monday)) && + weekDayData->getData(static_cast(WeekDayIso::Tuesday)) && + weekDayData->getData(static_cast(WeekDayIso::Wednesday)) && + weekDayData->getData(static_cast(WeekDayIso::Thursday)) && + weekDayData->getData(static_cast(WeekDayIso::Friday)); +} + +bool CustomRepeatValueParser::isCustomValueEveryday() const +{ + return isCustomValueWeekDays() && weekDayData->getData(static_cast(WeekDayIso::Saturday)) && + weekDayData->getData(static_cast(WeekDayIso::Sunday)); +} diff --git a/module-apps/application-alarm-clock/data/AlarmsData.hpp b/module-apps/application-alarm-clock/data/AlarmsData.hpp index fbea64190e8e7eb16fc306929ba140036c47553d..93521c571744f876781d5cbd219bb3185f683499 100644 --- a/module-apps/application-alarm-clock/data/AlarmsData.hpp +++ b/module-apps/application-alarm-clock/data/AlarmsData.hpp @@ -2,6 +2,8 @@ // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once + +#include "application-calendar/data/OptionParser.hpp" #include #include @@ -33,6 +35,17 @@ enum class AlarmAction Edit }; +enum class WeekDayIso +{ + Monday = date::Monday.iso_encoding() - 1, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday, + Sunday +}; + class AlarmRecordData : public gui::SwitchData { protected: @@ -41,7 +54,7 @@ class AlarmRecordData : public gui::SwitchData public: explicit AlarmRecordData(std::shared_ptr record) : record{std::move(record)} {} - std::shared_ptr getData() const + std::shared_ptr getData() { return record; } @@ -50,3 +63,15 @@ class AlarmRecordData : public gui::SwitchData record = std::move(rec); } }; + +class CustomRepeatValueParser +{ + std::unique_ptr weekDayData; + + public: + explicit CustomRepeatValueParser(uint32_t repeatValue); + + [[nodiscard]] std::string getWeekDaysText() const; + [[nodiscard]] bool isCustomValueWeekDays() const; + [[nodiscard]] bool isCustomValueEveryday() const; +}; diff --git a/module-apps/application-alarm-clock/models/CustomRepeatModel.cpp b/module-apps/application-alarm-clock/models/CustomRepeatModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4944e822a293ef6e9646fedbf73dcb179f3ad46a --- /dev/null +++ b/module-apps/application-alarm-clock/models/CustomRepeatModel.cpp @@ -0,0 +1,75 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "CustomRepeatModel.hpp" +#include "application-alarm-clock/widgets/CustomCheckBoxWithLabel.hpp" +#include "application-alarm-clock/widgets/AlarmClockStyle.hpp" +#include + +namespace app::alarmClock +{ + + CustomRepeatModel::CustomRepeatModel(app::Application *app, + std::shared_ptr alarmsRepository) + : application(app), alarmsRepository{std::move(alarmsRepository)} + {} + + unsigned int CustomRepeatModel::requestRecordsCount() + { + return internalData.size(); + } + + unsigned int CustomRepeatModel::getMinimalItemHeight() const + { + return style::alarmClock::window::item::checkBox::height; + } + + void CustomRepeatModel::requestRecords(uint32_t offset, uint32_t limit) + { + setupModel(offset, limit); + list->onProviderDataUpdate(); + } + + gui::ListItem *CustomRepeatModel::getItem(gui::Order order) + { + return getRecord(order); + } + + void CustomRepeatModel::createData(const WeekDaysRepeatData &data) + { + for (auto const &[key, dayName] : gui::CustomCheckBoxWithLabel::weekDays) { + internalData.push_back(new gui::CustomCheckBoxWithLabel(application, utils::localize.get(dayName), data)); + } + + for (auto &item : internalData) { + item->deleteByList = false; + } + } + + void CustomRepeatModel::loadData(const WeekDaysRepeatData &data) + { + list->clear(); + eraseInternalData(); + + createData(data); + + list->rebuildList(); + } + + std::vector CustomRepeatModel::getIsCheckedData() + { + std::vector isCheckedData; + isCheckedData.reserve(internalData.size()); + for (const auto &item : internalData) { + if (item->onContentChangedCallback) { + isCheckedData.push_back(item->onContentChangedCallback()); + } + else { + isCheckedData.push_back(false); + } + } + + return isCheckedData; + } + +} // namespace app::alarmClock diff --git a/module-apps/application-alarm-clock/models/CustomRepeatModel.hpp b/module-apps/application-alarm-clock/models/CustomRepeatModel.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b7e47d202e705844643e1a052de24e0058378738 --- /dev/null +++ b/module-apps/application-alarm-clock/models/CustomRepeatModel.hpp @@ -0,0 +1,43 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include "application-alarm-clock/widgets/AlarmInternalListItem.hpp" +#include "application-alarm-clock/models/AlarmsRepository.hpp" +#include "application-alarm-clock/data/AlarmsData.hpp" +#include "application-calendar/data/CalendarData.hpp" +#include "Application.hpp" +#include "InternalModel.hpp" +#include + +namespace app::alarmClock +{ + class CustomRepeatListItemProvider : public InternalModel, + public gui::ListItemProvider + { + public: + CustomRepeatListItemProvider() = default; + + virtual void loadData(const WeekDaysRepeatData &data) = 0; + virtual std::vector getIsCheckedData() = 0; + }; + + class CustomRepeatModel : public CustomRepeatListItemProvider + { + app::Application *application = nullptr; + std::shared_ptr alarmsRepository; + void createData(const WeekDaysRepeatData &data); + + public: + CustomRepeatModel(app::Application *app, std::shared_ptr alarmsRepository); + + [[nodiscard]] unsigned int getMinimalItemHeight() const override; + [[nodiscard]] unsigned int requestRecordsCount() override; + [[nodiscard]] gui::ListItem *getItem(gui::Order order) override; + void requestRecords(uint32_t offset, uint32_t limit) override; + + void loadData(const WeekDaysRepeatData &data) override; + std::vector getIsCheckedData() override; + }; +} // namespace app::alarmClock diff --git a/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp b/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp index 2c69a26f899ebc011cd7ff6a0b83948ef3b7bead..9c68889cd04e1e524d233389e90bc69aec3b53bd 100644 --- a/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp +++ b/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp @@ -57,11 +57,12 @@ namespace app::alarmClock [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text, false); }, [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); })); - internalData.push_back(new gui::AlarmOptionsItem( + repeatOption = new gui::AlarmOptionsItem( application, AlarmOptionItemName::Repeat, [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text, false); }, - [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); })); + [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); }); + internalData.push_back(repeatOption); for (auto &item : internalData) { item->deleteByList = false; @@ -84,6 +85,13 @@ namespace app::alarmClock list->rebuildList(); } + void NewEditAlarmModel::loadRepeat(std::shared_ptr record) + { + if (repeatOption->onLoadCallback) { + repeatOption->onLoadCallback(std::move(record)); + } + } + void NewEditAlarmModel::saveData(std::shared_ptr alarm, AlarmAction action) { for (auto &item : internalData) { diff --git a/module-apps/application-alarm-clock/models/NewEditAlarmModel.hpp b/module-apps/application-alarm-clock/models/NewEditAlarmModel.hpp index 29af81d6a572e7ceb812dd975125f4c0fe96792b..bf8227991dafb8fa987cc3043507ef155c5b4684 100644 --- a/module-apps/application-alarm-clock/models/NewEditAlarmModel.hpp +++ b/module-apps/application-alarm-clock/models/NewEditAlarmModel.hpp @@ -21,12 +21,14 @@ namespace app::alarmClock virtual void loadData(std::shared_ptr record) = 0; virtual void saveData(std::shared_ptr record, AlarmAction action) = 0; + virtual void loadRepeat(std::shared_ptr record) = 0; }; class NewEditAlarmModel : public AlarmsInternalListItemProvider { app::Application *application = nullptr; std::shared_ptr alarmsRepository; + gui::AlarmInternalListItem *repeatOption = nullptr; bool mode24H = false; public: @@ -36,6 +38,7 @@ namespace app::alarmClock void loadData(std::shared_ptr record) override; void saveData(std::shared_ptr alarm, AlarmAction action) override; + void loadRepeat(std::shared_ptr record) override; void createData(); [[nodiscard]] unsigned int getMinimalItemHeight() const override; diff --git a/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.cpp b/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.cpp index f6e3d29c42567f7100cd0d0fa89ac869f5f110f7..4fc1a19c54742544c03f802c5536324eb5cb5f6d 100644 --- a/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.cpp +++ b/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.cpp @@ -24,4 +24,16 @@ namespace app::alarmClock { alarmFieldsProvider->saveData(std::move(record), action); } + + void AlarmClockEditWindowPresenter::loadRepeat(std::shared_ptr record) + { + alarmFieldsProvider->loadRepeat(std::move(record)); + } + + void AlarmClockEditWindowPresenter::updateRepeat(std::shared_ptr record, WeekDaysRepeatData data) + { + auto parser = std::make_unique(); + auto uniqueData = std::make_unique(data); + record->repeat = parser->getDatabaseFieldValue(std::move(uniqueData)); + } } // namespace app::alarmClock diff --git a/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.hpp b/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.hpp index 3b9f837d0821d1fd6b5b67ae41bb67982c03b179..978c2e2dd32f5ebfb74fd185c88ab6a93dce2b50 100644 --- a/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.hpp +++ b/module-apps/application-alarm-clock/presenter/AlarmClockEditWindowPresenter.hpp @@ -25,6 +25,8 @@ namespace app::alarmClock [[nodiscard]] virtual std::shared_ptr getAlarmsItemProvider() const = 0; virtual void loadData(std::shared_ptr record) = 0; virtual void saveData(std::shared_ptr record, AlarmAction action) = 0; + virtual void loadRepeat(std::shared_ptr record) = 0; + virtual void updateRepeat(std::shared_ptr record, WeekDaysRepeatData data) = 0; }; }; @@ -36,6 +38,8 @@ namespace app::alarmClock [[nodiscard]] std::shared_ptr getAlarmsItemProvider() const override; void loadData(std::shared_ptr record) override; void saveData(std::shared_ptr record, AlarmAction action) override; + void loadRepeat(std::shared_ptr record) override; + void updateRepeat(std::shared_ptr record, WeekDaysRepeatData data) override; private: std::shared_ptr alarmFieldsProvider; diff --git a/module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.cpp b/module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..412128f59cc8558cc920e559e242cab67439f607 --- /dev/null +++ b/module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.cpp @@ -0,0 +1,34 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "CustomRepeatWindowPresenter.hpp" + +namespace app::alarmClock +{ + + CustomRepeatWindowPresenter::CustomRepeatWindowPresenter(std::shared_ptr itemProvider) + : customRepeatProvider{std::move(itemProvider)} + {} + + std::shared_ptr CustomRepeatWindowPresenter::getItemProvider() + { + return customRepeatProvider; + } + + void CustomRepeatWindowPresenter::loadData(const WeekDaysRepeatData &data) + { + customRepeatProvider->loadData(data); + } + + WeekDaysRepeatData CustomRepeatWindowPresenter::getWeekDaysRepeatData() + { + auto weekDaysOptData = WeekDaysRepeatData(); + auto isCheckedData = customRepeatProvider->getIsCheckedData(); + uint32_t i = 0; + for (const auto &checked : isCheckedData) { + weekDaysOptData.setData(i, checked); + ++i; + } + return weekDaysOptData; + } +} // namespace app::alarmClock diff --git a/module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.hpp b/module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..47cc50c850d3e8cebe73fdfa49c2ad79f31e67f3 --- /dev/null +++ b/module-apps/application-alarm-clock/presenter/CustomRepeatWindowPresenter.hpp @@ -0,0 +1,43 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include "BasePresenter.hpp" +#include "application-alarm-clock/data/AlarmsData.hpp" +#include "application-alarm-clock/models/CustomRepeatModel.hpp" + +namespace app::alarmClock +{ + class CustomRepeatWindowContract + { + public: + class View + { + public: + virtual ~View() noexcept = default; + }; + class Presenter : public BasePresenter + { + public: + virtual ~Presenter() noexcept = default; + + [[nodiscard]] virtual std::shared_ptr getItemProvider() = 0; + virtual void loadData(const WeekDaysRepeatData &data) = 0; + virtual WeekDaysRepeatData getWeekDaysRepeatData() = 0; + }; + }; + + class CustomRepeatWindowPresenter : public CustomRepeatWindowContract::Presenter + { + public: + explicit CustomRepeatWindowPresenter(std::shared_ptr itemProvider); + + [[nodiscard]] std::shared_ptr getItemProvider() override; + void loadData(const WeekDaysRepeatData &data) override; + WeekDaysRepeatData getWeekDaysRepeatData() override; + + private: + std::shared_ptr customRepeatProvider; + }; +} // namespace app::alarmClock diff --git a/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp b/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp index f27f578110b20b58737b831885665ccc7c93d3c2..59b95a9559af2416229605939a56ea72776d5232 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp +++ b/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp @@ -54,6 +54,14 @@ namespace style::alarmClock inline constexpr auto label_h = 30; inline constexpr auto arrow_w_h = 20; } // namespace options + + namespace checkBox + { + inline constexpr auto height = 44; + inline constexpr auto marginTop = 18; + inline constexpr auto inputBox_w = style::window::label::big_h; + inline constexpr auto description_w = 280; + } // namespace checkBox } // namespace item } // namespace window diff --git a/module-apps/application-alarm-clock/widgets/AlarmInternalListItem.hpp b/module-apps/application-alarm-clock/widgets/AlarmInternalListItem.hpp index 19ab97478f840d8aa4994d6aa549c49b78b0ebe5..62e2f7a5fa04cf35d8e0b60284de40ec9f5679e5 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmInternalListItem.hpp +++ b/module-apps/application-alarm-clock/widgets/AlarmInternalListItem.hpp @@ -12,6 +12,7 @@ namespace gui public: std::function event)> onSaveCallback = nullptr; std::function event)> onLoadCallback = nullptr; + std::function onContentChangedCallback = nullptr; }; } /* namespace gui */ diff --git a/module-apps/application-alarm-clock/widgets/AlarmItem.cpp b/module-apps/application-alarm-clock/widgets/AlarmItem.cpp index 5777256f3c600761570d679d42a0198d78495cce..b889aa566cb7e209cce7e6ff27b8c32b7baafa1b 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmItem.cpp +++ b/module-apps/application-alarm-clock/widgets/AlarmItem.cpp @@ -66,7 +66,7 @@ namespace gui periodLabel->setText(utils::localize.get("app_alarm_clock_repeat_week_days")); } else if (alarm->repeat != static_cast(AlarmRepeat::never)) { - periodLabel->setText(utils::localize.get("app_alarm_clock_repeat_custom")); + periodLabel->setText(CustomRepeatValueParser(alarm->repeat).getWeekDaysText()); } if (periodLabel->getText().empty()) { diff --git a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp index 8504f8498c2dfa9025172c825f318a3f1a4a1744..564af088c6dafa69871e31da01cef2991a7c3109 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp +++ b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp @@ -142,11 +142,20 @@ namespace gui if (event.state != gui::InputEvent::State::keyReleasedShort) { return false; } + if (event.is(gui::KeyCode::KEY_RF)) { + setFocusItem(nullptr); + } if (event.is(gui::KeyCode::KEY_LEFT)) { actualVectorIndex--; if (actualVectorIndex >= optionsNames.size()) { actualVectorIndex = optionsNames.size() - 1; + if (itemName == AlarmOptionItemName::Repeat) { + bottomBarTemporaryMode(utils::localize.get("app_alarm_clock_edit")); + } + } + else if (itemName == AlarmOptionItemName::Repeat) { + bottomBarRestoreFromTemporaryMode(); } optionLabel->setText(optionsNames[actualVectorIndex]); return true; @@ -157,10 +166,24 @@ namespace gui if (actualVectorIndex >= optionsNames.size()) { actualVectorIndex = 0; } + if (actualVectorIndex == optionsNames.size() - 1 && itemName == AlarmOptionItemName::Repeat) { + bottomBarTemporaryMode(utils::localize.get("app_alarm_clock_edit")); + } + else if (itemName == AlarmOptionItemName::Repeat) { + bottomBarRestoreFromTemporaryMode(); + } optionLabel->setText(optionsNames[actualVectorIndex]); return true; } + if (event.is(gui::KeyCode::KEY_LF) && itemName == AlarmOptionItemName::Repeat && + actualVectorIndex == optionsNames.size() - 1) { + OptionParser parser; + auto weekDayRepeatData = std::make_unique(); + auto weekDayData = parser.setWeekDayOptions(repeatOptionValue, std::move(weekDayRepeatData)); + application->switchWindow(style::alarmClock::window::name::customRepeat, std::move(weekDayData)); + } + if (event.is(gui::KeyCode::KEY_LF) && itemName == AlarmOptionItemName::Sound) { if (musicStatus == MusicStatus::Stop) { musicStatus = MusicStatus::Play; @@ -186,7 +209,14 @@ namespace gui break; } case AlarmOptionItemName::Repeat: { - alarm->repeat = actualVectorIndex; + if (alarm->repeat < optionsNames.size() - 1 && actualVectorIndex != optionsNames.size() - 1) { + alarm->repeat = actualVectorIndex; + } + else if (alarm->repeat == optionsNames.size() - 1 || + optionsNames[optionsNames.size() - 1] == + utils::localize.get("app_alarm_clock_repeat_custom")) { + alarm->repeat = static_cast(AlarmRepeat::never); + } break; } } @@ -221,10 +251,34 @@ namespace gui case AlarmOptionItemName::Repeat: { if (alarm->repeat < optionsNames.size() - 1) { actualVectorIndex = alarm->repeat; + if (alarm->repeat == static_cast(AlarmRepeat::never)) { + optionsNames[optionsNames.size() - 1] = utils::localize.get("app_alarm_clock_repeat_custom"); + } + bottomBarRestoreFromTemporaryMode(); } else { - actualVectorIndex = optionsNames.size() - 1; + auto parser = CustomRepeatValueParser(alarm->repeat); + if (parser.isCustomValueEveryday()) { + actualVectorIndex = static_cast(AlarmRepeat::everyday); + alarm->repeat = actualVectorIndex; + bottomBarRestoreFromTemporaryMode(); + optionsNames[optionsNames.size() - 1] = utils::localize.get("app_alarm_clock_repeat_custom"); + } + else if (parser.isCustomValueWeekDays()) { + actualVectorIndex = static_cast(AlarmRepeat::weekDays); + alarm->repeat = actualVectorIndex; + bottomBarRestoreFromTemporaryMode(); + optionsNames[optionsNames.size() - 1] = utils::localize.get("app_alarm_clock_repeat_custom"); + } + else { + actualVectorIndex = optionsNames.size() - 1; + optionsNames[optionsNames.size() - 1] = parser.getWeekDaysText(); + if (this->focus) { + bottomBarTemporaryMode(utils::localize.get("app_alarm_clock_edit")); + } + } } + repeatOptionValue = alarm->repeat; break; } } @@ -260,5 +314,4 @@ namespace gui LOG_INFO("Total number of music files found: %u", static_cast(musicFiles.size())); return musicFiles; } - } /* namespace gui */ diff --git a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp index d342e36cc5652f19bc4e5f10f1a2c61efcece7ce..4891a19c725f9979d67ab3afd064bc980e12c41c 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp +++ b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp @@ -34,6 +34,7 @@ namespace gui std::vector songsList; MusicStatus musicStatus = MusicStatus::Stop; unsigned int actualVectorIndex = 0; + uint32_t repeatOptionValue = 0; std::function bottomBarTemporaryMode = nullptr; std::function bottomBarRestoreFromTemporaryMode = nullptr; diff --git a/module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.cpp b/module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..29883e7bc6a4db90d726053b7ed76056e86e9739 --- /dev/null +++ b/module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.cpp @@ -0,0 +1,100 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "CustomCheckBoxWithLabel.hpp" +#include "AlarmClockStyle.hpp" +#include + +namespace gui +{ + const std::map CustomCheckBoxWithLabel::weekDays = { + {WeekDayIso::Monday, style::strings::common::Monday}, + {WeekDayIso::Tuesday, style::strings::common::Tuesday}, + {WeekDayIso::Wednesday, style::strings::common::Wednesday}, + {WeekDayIso::Thursday, style::strings::common::Thursday}, + {WeekDayIso::Friday, style::strings::common::Friday}, + {WeekDayIso::Saturday, style::strings::common::Saturday}, + {WeekDayIso::Sunday, style::strings::common::Sunday}}; + + CustomCheckBoxWithLabel::CustomCheckBoxWithLabel(app::Application *app, + const std::string &description, + const WeekDaysRepeatData &data) + : application(app), checkBoxData(data) + { + assert(application != nullptr); + + setMinimumSize(style::window::default_body_width, style::alarmClock::window::item::checkBox::height); + setMargins(gui::Margins(style::margins::small, style::alarmClock::window::item::checkBox::marginTop, 0, 0)); + setEdges(RectangleEdge::None); + + hBox = new gui::HBox(this, 0, 0, 0, 0); + hBox->setEdges(gui::RectangleEdge::None); + + checkBox = new gui::CheckBox( + hBox, + 0, + 0, + 0, + 0, + [=](const UTF8 &text) { application->getCurrentWindow()->bottomBarTemporaryMode(text, false); }, + [=]() { application->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); }); + checkBox->setMinimumSize(style::alarmClock::window::item::checkBox::inputBox_w, + style::alarmClock::window::item::checkBox::height); + + descriptionLabel = new gui::Label(hBox, 0, 0, 0, 0); + descriptionLabel->setMinimumSize(style::alarmClock::window::item::checkBox::description_w, + style::alarmClock::window::item::checkBox::height); + descriptionLabel->setMargins(gui::Margins(style::margins::very_big, 0, 0, 0)); + descriptionLabel->setEdges(gui::RectangleEdge::None); + descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center)); + descriptionLabel->setFont(style::window::font::medium); + descriptionLabel->setText(description); + + applyCallbacks(); + setCheckBoxes(); + } + + void CustomCheckBoxWithLabel::applyCallbacks() + { + focusChangedCallback = [&](Item &item) { + if (focus) { + descriptionLabel->setFont(style::window::font::mediumbold); + setFocusItem(checkBox); + } + else { + descriptionLabel->setFont(style::window::font::medium); + setFocusItem(nullptr); + } + return true; + }; + + inputCallback = [&](gui::Item &item, const gui::InputEvent &event) { + if (event.is(gui::KeyCode::KEY_RF) || event.is(gui::KeyCode::KEY_ENTER)) { + setFocusItem(nullptr); + return false; + } + if (checkBox->onInput(event)) { + checkBox->resizeItems(); + return true; + } + return false; + }; + onContentChangedCallback = [&]() { return checkBox->isChecked(); }; + } + + void CustomCheckBoxWithLabel::setCheckBoxes() + { + for (auto const &[key, dayName] : weekDays) { + if (descriptionLabel->getText() == utils::localize.get(dayName)) { + checkBox->setImageVisible(checkBoxData.getData(static_cast(key))); + } + } + } + + bool CustomCheckBoxWithLabel::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) + { + hBox->setPosition(0, 0); + hBox->setSize(newDim.w, newDim.h); + return true; + } +} // namespace gui diff --git a/module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.hpp b/module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bac4c3a4e74fb547baa19ff29746d3c12951a4dc --- /dev/null +++ b/module-apps/application-alarm-clock/widgets/CustomCheckBoxWithLabel.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include "AlarmInternalListItem.hpp" +#include "application-alarm-clock/data/AlarmsData.hpp" +#include "Application.hpp" +#include "application-calendar/data/CalendarData.hpp" +#include +#include + +namespace gui +{ + class CustomCheckBoxWithLabel : public AlarmInternalListItem + { + gui::HBox *hBox = nullptr; + app::Application *application = nullptr; + gui::Label *descriptionLabel = nullptr; + gui::CheckBox *checkBox = nullptr; + WeekDaysRepeatData checkBoxData; + + void setCheckBoxes(); + void applyCallbacks(); + + public: + CustomCheckBoxWithLabel(app::Application *app, const std::string &description, const WeekDaysRepeatData &data); + + bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override; + + static const std::map weekDays; + }; +} // namespace gui diff --git a/module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp b/module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad38d2551d7459fe117aaf0deba64fd061a68f47 --- /dev/null +++ b/module-apps/application-alarm-clock/windows/CustomRepeatWindow.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "CustomRepeatWindow.hpp" + +namespace app::alarmClock +{ + + CustomRepeatWindow::CustomRepeatWindow(app::Application *app, + std::unique_ptr &&windowPresenter) + : AppWindow(app, style::alarmClock::window::name::customRepeat), presenter{std::move(windowPresenter)} + { + presenter->attach(this); + buildInterface(); + } + + void CustomRepeatWindow::buildInterface() + { + AppWindow::buildInterface(); + + topBar->setActive(gui::TopBar::Elements::TIME, true); + topBar->setActive(gui::TopBar::Elements::SIM, false); + topBar->setActive(gui::TopBar::Elements::NETWORK_ACCESS_TECHNOLOGY, false); + bottomBar->setActive(gui::BottomBar::Side::RIGHT, true); + bottomBar->setActive(gui::BottomBar::Side::CENTER, true); + bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back)); + bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::save)); + + setTitle(utils::localize.get("app_calendar_custom_repeat_title")); + list = new gui::ListView(this, + style::alarmClock::window::listView_x, + style::alarmClock::window::listView_y, + style::alarmClock::window::listView_w, + style::alarmClock::window::listView_h, + presenter->getItemProvider()); + setFocusItem(list); + } + + void CustomRepeatWindow::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) + { + if (auto receivedData = dynamic_cast(data); receivedData != nullptr) { + weekDaysOptData = *receivedData; + } + else { + weekDaysOptData = WeekDaysRepeatData(); + } + presenter->loadData(weekDaysOptData); + } + + bool CustomRepeatWindow::onInput(const gui::InputEvent &inputEvent) + { + if (AppWindow::onInput(inputEvent)) { + return true; + } + + if (inputEvent.isShortPress() && inputEvent.is(gui::KeyCode::KEY_ENTER)) { + weekDaysOptData = presenter->getWeekDaysRepeatData(); + application->switchWindow(style::alarmClock::window::name::newEditAlarm, + gui::ShowMode::GUI_SHOW_RETURN, + std::make_unique(weekDaysOptData)); + return true; + } + return false; + } +} // namespace app::alarmClock diff --git a/module-apps/application-alarm-clock/windows/CustomRepeatWindow.hpp b/module-apps/application-alarm-clock/windows/CustomRepeatWindow.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d840063471fa11b08991181b68da1a1b4c326164 --- /dev/null +++ b/module-apps/application-alarm-clock/windows/CustomRepeatWindow.hpp @@ -0,0 +1,30 @@ +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include "application-alarm-clock/widgets/AlarmClockStyle.hpp" +#include "application-alarm-clock/presenter/CustomRepeatWindowPresenter.hpp" +#include "application-alarm-clock/data/AlarmsData.hpp" +#include "Application.hpp" +#include +#include + +namespace app::alarmClock +{ + class CustomRepeatWindow : public gui::AppWindow, public CustomRepeatWindowContract::View + { + gui::ListView *list = nullptr; + std::unique_ptr presenter; + WeekDaysRepeatData weekDaysOptData; + + public: + CustomRepeatWindow(app::Application *app, + std::unique_ptr &&windowPresenter); + + void onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) override; + bool onInput(const gui::InputEvent &inputEvent) override; + void buildInterface() override; + }; + +} // namespace app::alarmClock diff --git a/module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp b/module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp index ba1ecd402e623d2074a922318c910f8ff9c3b1bd..10d50a8f1df93461182d9cd16199f4b76d0fdb02 100644 --- a/module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp +++ b/module-apps/application-alarm-clock/windows/NewEditAlarmWindow.cpp @@ -3,6 +3,7 @@ #include "NewEditAlarmWindow.hpp" #include "application-alarm-clock/data/AlarmsData.hpp" +#include "application-calendar/data/OptionParser.hpp" #include namespace app::alarmClock @@ -53,6 +54,13 @@ namespace app::alarmClock } presenter->loadData(alarmRecord); } + + if (mode == gui::ShowMode::GUI_SHOW_RETURN) { + if (auto receivedData = dynamic_cast(data); receivedData != nullptr) { + presenter->updateRepeat(alarmRecord, *receivedData); + presenter->loadRepeat(alarmRecord); + } + } } bool NewEditAlarmWindow::onInput(const gui::InputEvent &inputEvent)