From d9612efe7a702e82d3b9540d348fd7772a428575 Mon Sep 17 00:00:00 2001 From: mkamonMdt Date: Thu, 7 Jan 2021 16:44:09 +0100 Subject: [PATCH] [EGD-4338] Fix menu notification dot Each tile in Menu that uses notification dot is be refreshed. It also solves missing dot issue of EGD-4129 and lack of sound notification on incoming text message. --- changelog.md | 1 + .../ApplicationDesktop.cpp | 7 +- .../windows/MenuWindow.cpp | 91 +++++++++++++++---- .../windows/MenuWindow.hpp | 11 ++- module-gui/gui/widgets/Item.cpp | 5 - module-gui/gui/widgets/Item.hpp | 7 -- .../service-cellular/ServiceCellular.cpp | 3 + 7 files changed, 89 insertions(+), 36 deletions(-) diff --git a/changelog.md b/changelog.md index ef5410a46913ddea28d9bc1f38ca527b3c209c55..709c848045329f58f54be5f122302ba84a4e0f3d 100644 --- a/changelog.md +++ b/changelog.md @@ -22,6 +22,7 @@ ### Fixed +* Fix menu notification dot * Fix absent notifications * Fix newly added contact recognized as a duplicate of temporary contact. * Fix default borderCallback navigation in GridLayout. diff --git a/module-apps/application-desktop/ApplicationDesktop.cpp b/module-apps/application-desktop/ApplicationDesktop.cpp index 352bc2282f740db7514b887f9eca6707a604d5d2..eb9d4ad451084714dca669ada2b5cfd4a227a911 100644 --- a/module-apps/application-desktop/ApplicationDesktop.cpp +++ b/module-apps/application-desktop/ApplicationDesktop.cpp @@ -203,7 +203,11 @@ namespace app msg->interface == db::Interface::Name::SMS) && msg->type != db::Query::Type::Read) { requestNotReadNotifications(); - windowsFactory.build(this, app::window::name::desktop_menu); + if (auto menuWindow = dynamic_cast(getWindow(app::window::name::desktop_menu)); + menuWindow != nullptr) { + menuWindow->refresh(); + return true; + } } return false; @@ -266,7 +270,6 @@ namespace app { notifications.notRead.Calls = DBServiceAPI::CalllogGetCount(this, EntryState::UNREAD); notifications.notRead.SMS = DBServiceAPI::ThreadGetCount(this, EntryState::UNREAD); - return true; } diff --git a/module-apps/application-desktop/windows/MenuWindow.cpp b/module-apps/application-desktop/windows/MenuWindow.cpp index 290ea1af77df7c657b14ae80c9f635a2a00b4212..f726cd81bf5ac4a7d00480289245145d763c4944 100644 --- a/module-apps/application-desktop/windows/MenuWindow.cpp +++ b/module-apps/application-desktop/windows/MenuWindow.cpp @@ -24,16 +24,33 @@ namespace style::design inline const auto notify_dot_x = 80; inline const auto notify_dot_y = (64 - 50) / 2; inline const auto grid_offset = 20; -}; // namespace style::design +} // namespace style::design + +namespace +{ + static constexpr auto deepRefreshDot = "dot_12px_hard_alpha_W_G"; + static constexpr auto fastRefreshDot = "dot_12px_hard_alpha_W_M"; + + gui::Image *buildThumbnail(gui::RefreshModes mode) + { + gui::Image *thumbnail = + new gui::Image(mode == gui::RefreshModes::GUI_REFRESH_DEEP ? deepRefreshDot : fastRefreshDot); + thumbnail->setPosition(style::design::notify_dot_x, style::design::notify_dot_y); + return thumbnail; + } +} // namespace namespace gui { inline const auto APP_SETTINGS_NEW = "ApplicationSettingsNew"; - Tile::Tile(UTF8 icon, std::string title, std::function activatedCallback, unsigned int notifications) + Tile::Tile(UTF8 icon, + std::string title, + std::function activatedCallback, + std::function hasNotificationsCallback) { setSize(style::design::tile_w, style::design::tile_h); - auto *it = new gui::Item(); + auto it = new gui::Item(); it->setSize(style::design::tile_w, style::design::tile_h - 2 * style::design::tile_margin); it->setPosition(area().x, area().y + style::design::tile_margin); @@ -48,10 +65,21 @@ namespace gui desc->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Bottom)); desc->setText(utils::localize.get(title)); - if (notifications > 0) { - auto thumbnail = new gui::Image("dot_12px_hard_alpha_W_G"); - thumbnail->setPosition(style::design::notify_dot_x, style::design::notify_dot_y); - it->addWidget(thumbnail); + if (hasNotificationsCallback != nullptr) { + onNotificationsChangeCallback = + [this, it, hasNotifications = std::move(hasNotificationsCallback)](gui::RefreshModes mode) -> bool { + if (hasNotifications() && notificationThumbnail == nullptr) { + notificationThumbnail = buildThumbnail(mode); + it->addWidget(notificationThumbnail); + return true; + } + else if (!hasNotifications() && notificationThumbnail != nullptr) { + it->erase(notificationThumbnail); + notificationThumbnail = nullptr; + } + return false; + }; + onNotificationsChangeCallback(gui::RefreshModes::GUI_REFRESH_DEEP); } this->activatedCallback = activatedCallback; @@ -59,9 +87,16 @@ namespace gui this->setPenFocusWidth(style::window::default_border_focus_w); this->setEdges(RectangleEdge::Top | RectangleEdge::Bottom); addWidget(it); - }; + } + bool Tile::onNotificationsChange(gui::RefreshModes mode) + { + if (onNotificationsChangeCallback != nullptr) { + return onNotificationsChangeCallback(mode); + } + return false; + } - MenuPage::MenuPage(gui::Item *parent, UTF8 title, std::vector tiles) : title(title) + MenuPage::MenuPage(gui::Item *parent, UTF8 title, std::vector tiles) : title(std::move(title)) { if (parent) { parent->addWidget(this); @@ -83,6 +118,17 @@ namespace gui } } + bool MenuPage::refresh(gui::RefreshModes mode) + { + bool visibleStateChanged = false; + for (auto child : children) { + if (auto tile = dynamic_cast(child); tile != nullptr) { + visibleStateChanged |= tile->onNotificationsChange(mode); + } + } + return visibleStateChanged; + } + MenuWindow::MenuWindow(app::Application *app) : AppWindow(app, app::window::name::desktop_menu) { buildInterface(); @@ -150,7 +196,8 @@ namespace gui app::manager::actions::Launch, std::make_unique("ApplicationCallLog")); }, - app->notifications.notRead.Calls}, + [=]() { return app->notifications.notRead.Calls > 0; }}, + new gui::Tile("menu_contacts_W_G", "app_desktop_menu_contacts", [=](gui::Item &item) { @@ -168,7 +215,7 @@ namespace gui app::manager::actions::Launch, std::make_unique("ApplicationMessages")); }, - app->notifications.notRead.SMS}, + [=]() { return app->notifications.notRead.SMS > 0; }}, new gui::Tile{"menu_music_player_W_G", "app_desktop_menu_music", [=](gui::Item &item) { @@ -185,15 +232,12 @@ namespace gui app::manager::actions::Launch, std::make_unique("ApplicationMeditation")); }}, - new gui::Tile{"menu_settings_W_G", - "app_desktop_menu_settings_new", - [=](gui::Item &item) { + new gui::Tile{"menu_settings_W_G", "app_desktop_menu_settings_new", [=](gui::Item &item) { return app::manager::Controller::sendAction( application, app::manager::actions::Launch, std::make_unique(APP_SETTINGS_NEW)); - }}, - }); + }}}); toolsMenu = new MenuPage( this, @@ -254,9 +298,6 @@ namespace gui toolsMenu = nullptr; } - void MenuWindow::onBeforeShow(ShowMode mode, SwitchData *data) - {} - bool MenuWindow::onInput(const InputEvent &inputEvent) { if ((inputEvent.state == InputEvent::State::keyReleasedShort) && (inputEvent.keyCode == KeyCode::KEY_RF) && @@ -278,7 +319,17 @@ namespace gui setTitle(page->title); setFocusItem(page); - application->refreshWindow(gui::RefreshModes::GUI_REFRESH_DEEP); } + void MenuWindow::refresh() + { + if (application->getCurrentWindow() == this) { + if (mainMenu->refresh(RefreshModes::GUI_REFRESH_FAST)) { + application->refreshWindow(RefreshModes::GUI_REFRESH_FAST); + } + } + else { + mainMenu->refresh(RefreshModes::GUI_REFRESH_DEEP); + } + } } /* namespace gui */ diff --git a/module-apps/application-desktop/windows/MenuWindow.hpp b/module-apps/application-desktop/windows/MenuWindow.hpp index 0ba686e01663d2f0c4fa1a6c6c32f68c74502a1c..7f3f39c782054dd9a5f27474433cebc722d06f32 100644 --- a/module-apps/application-desktop/windows/MenuWindow.hpp +++ b/module-apps/application-desktop/windows/MenuWindow.hpp @@ -22,7 +22,13 @@ namespace gui Tile(UTF8 icon, std::string title, std::function activatedCallback, - unsigned int notifications = 0); + std::function hasNotificationsCallback = nullptr); + + bool onNotificationsChange(gui::RefreshModes); + + private: + std::function onNotificationsChangeCallback = nullptr; + gui::Image *notificationThumbnail = nullptr; }; class MenuPage : public gui::GridLayout @@ -36,6 +42,7 @@ namespace gui MenuPage(gui::Item *parent, UTF8 title, std::vector tiles); /// set child which should be selected on start of desktop void setFirstTimeSelection(); + bool refresh(gui::RefreshModes mode); }; class MenuWindow : public AppWindow @@ -48,7 +55,6 @@ namespace gui public: MenuWindow(app::Application *app); - void onBeforeShow(ShowMode mode, SwitchData *data) override; bool onInput(const InputEvent &inputEvent) override; void rebuild() override; @@ -56,6 +62,7 @@ namespace gui void destroyInterface() override; void switchMenu(MenuPage *page); + void refresh(); private: void invalidate() noexcept; diff --git a/module-gui/gui/widgets/Item.cpp b/module-gui/gui/widgets/Item.cpp index c1dc8baaee603bfc11f4535f8adf48a177bea725..e0bddcbebef92179d65fcbd5b8658a15f3cfbce2 100644 --- a/module-gui/gui/widgets/Item.cpp +++ b/module-gui/gui/widgets/Item.cpp @@ -515,11 +515,6 @@ namespace gui return false; } - bool Item::onContent() - { - return false; - } - auto Item::onTimer(Timer &timer) -> bool { if (timerCallback != nullptr) { diff --git a/module-gui/gui/widgets/Item.hpp b/module-gui/gui/widgets/Item.hpp index 989198ebfb8ee4c897213677cdcced88919bbf59..e84f71334a3b872bf52c94e5289313d8fa18e382 100644 --- a/module-gui/gui/widgets/Item.hpp +++ b/module-gui/gui/widgets/Item.hpp @@ -139,9 +139,6 @@ namespace gui /// @param `this` item /// @param `InputEvent` std::function inputCallback; - /// callback when element insides are changed - /// @param `this` item - std::function contentCallback; /// callback when timer is called on Item and onTimer is executed /// @param `this` item /// @param `timer` which triggered this callback @@ -183,10 +180,6 @@ namespace gui /// calls: none, inconsistent api /// @note TODO should be fixed so that api would be consistent virtual bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim); - /// (should be) called each time content in item was changed, added for gui::Text widget - /// calls: none, inconsistent behaviour - /// @note TODO should be fixed so that api would be consistent - virtual bool onContent(); /// called on Timer event in application, triggeres timerCallback /// @param timer timer element which triggered this action virtual bool onTimer(Timer &timer); diff --git a/module-services/service-cellular/ServiceCellular.cpp b/module-services/service-cellular/ServiceCellular.cpp index 66c8186f699a102e29829a0f8ee81c8bb12c44dd..3962352dea060ae3d760c41b6b09916aba9d47c0 100644 --- a/module-services/service-cellular/ServiceCellular.cpp +++ b/module-services/service-cellular/ServiceCellular.cpp @@ -1044,6 +1044,9 @@ sys::MessagePointer ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl, if (auto response = dynamic_cast(result.get())) { responseHandled = handle(response); } + else if (result->hasListener()) { + responseHandled = result->handle(); + } } if (responseHandled) { return std::make_shared();