M module-apps/Application.cpp => module-apps/Application.cpp +11 -0
@@ 25,6 25,7 @@
#include <service-evtmgr/EVMessages.hpp>
#include <service-appmgr/service-appmgr/messages/DOMRequest.hpp>
#include <service-appmgr/messages/UserPowerDownRequest.hpp>
+#include <service-appmgr/data/NotificationsChangedActionsParams.hpp>
#include "service-gui/messages/DrawMessage.hpp" // for DrawMessage
#include "task.h" // for xTaskGetTic...
#include "windows/AppWindow.hpp" // for AppWindow
@@ 132,6 133,11 @@ namespace app
abortPopup(popupId);
return actionHandled();
});
+ addActionReceiver(app::manager::actions::NotificationsChanged, [this](auto &¶ms) {
+ auto notificationParams = static_cast<manager::actions::NotificationsChangedParams *>(params.get());
+ handle(notificationParams);
+ return actionHandled();
+ });
}
Application::~Application() noexcept
@@ 864,6 870,11 @@ namespace app
receivers.insert_or_assign(actionId, std::move(callback));
}
+ void Application::handle(manager::actions::NotificationsChangedParams *params)
+ {
+ LOG_DEBUG("To be implemented by Pop-up based Locked-Screen [EGD-5884]");
+ }
+
void Application::cancelCallbacks(AsyncCallbackReceiver::Ptr receiver)
{
callbackStorage->removeAll(receiver);
M module-apps/Application.hpp => module-apps/Application.hpp +7 -10
@@ 36,24 36,20 @@
namespace app
{
class WindowsStack;
+
+ namespace manager::actions
+ {
+ class NotificationsChangedParams;
+ }
} // namespace app
namespace gui
{
class AppWindow;
-} // namespace gui
-namespace gui
-{
class InputEvent;
-}
-namespace gui
-{
class Item;
class PopupRequestParams;
-}
-namespace gui
-{
class KeyInputSimpleTranslation;
-}
+} // namespace gui
namespace settings
{
class Settings;
@@ 394,6 390,7 @@ namespace app
const gui::InputEvent &event);
void addActionReceiver(manager::actions::ActionId actionId, OnActionReceived &&callback);
+ virtual void handle(manager::actions::NotificationsChangedParams *params);
std::unique_ptr<TopBarManager> topBarManager;
M module-apps/CMakeLists.txt => module-apps/CMakeLists.txt +4 -1
@@ 46,6 46,9 @@ set( SOURCES
"widgets/DateWidget.cpp"
"widgets/TimeWidget.cpp"
"widgets/WidgetsUtils.cpp"
+ "notifications/NotificationListItem.cpp"
+ "notifications/NotificationsModel.cpp"
+ "notifications/NotificationProvider.cpp"
"options/OptionsModel.cpp"
"options/type/OptionSimple.cpp"
"options/type/OptionCall.cpp"
@@ 53,7 56,7 @@ set( SOURCES
"options/type/OptionSetting.cpp"
"options/type/OptionChangePin.cpp"
"options/type/OptionWithActiveIcons.cpp"
- "application-desktop/windows/UpdateProgress.cpp")
+ "notifications/NotificationData.cpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${BOARD_SOURCES})
M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +12 -74
@@ 26,6 26,7 @@
#include "AppWindow.hpp"
#include "data/LockPhoneData.hpp"
+#include "models/ActiveNotificationsModel.hpp"
#include <service-db/DBServiceAPI.hpp>
#include <application-settings-new/ApplicationSettings.hpp>
@@ 50,12 51,6 @@ namespace app
namespace
{
- bool requestNotSeenNotifications(app::Application *app)
- {
- const auto [succeed, _] = DBServiceAPI::GetQuery(
- app, db::Interface::Name::Notifications, std::make_unique<db::query::notifications::GetAll>());
- return succeed;
- }
bool requestUnreadThreadsCount(app::Application *app)
{
@@ 76,7 71,8 @@ namespace app
std::string parent,
sys::phone_modes::PhoneMode mode,
StartInBackground startInBackground)
- : Application(name, parent, mode, startInBackground), lockHandler(this)
+ : Application(std::move(name), std::move(parent), mode, startInBackground),
+ lockHandler(this), notificationsModel{std::make_shared<gui::ActiveNotificationsModel>()}
{
using namespace gui::top_bar;
topBarManager->enableIndicators({Indicator::Signal,
@@ 185,9 181,6 @@ namespace app
return actionHandled();
});
}
- ApplicationDesktop::~ApplicationDesktop()
- {
- }
// Invoked upon receiving data message
sys::MessagePointer ApplicationDesktop::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
@@ 219,9 212,6 @@ namespace app
if (resp != nullptr) {
if (auto msg = dynamic_cast<db::QueryResponse *>(resp)) {
auto result = msg->getResult();
- if (auto response = dynamic_cast<db::query::notifications::GetAllResult *>(result.get())) {
- handled = handle(response);
- }
if (auto response = dynamic_cast<db::query::ThreadGetCountResult *>(result.get())) {
handled = handle(response);
}
@@ 262,48 252,17 @@ namespace app
return true;
}
- auto ApplicationDesktop::handle(db::query::notifications::GetAllResult *msg) -> bool
+ void ApplicationDesktop::handle(manager::actions::NotificationsChangedParams *params)
{
- assert(msg);
- auto records = *msg->getResult();
-
- bool rebuildMainWindow = false;
-
- for (auto record : records) {
- switch (record.key) {
- case NotificationsRecord::Key::Calls:
- rebuildMainWindow |= record.value != notifications.notSeen.Calls;
- notifications.notSeen.Calls = record.value;
- break;
-
- case NotificationsRecord::Key::Sms:
- rebuildMainWindow |= record.value != notifications.notSeen.SMS;
- notifications.notSeen.SMS = record.value;
- break;
-
- case NotificationsRecord::Key::NotValidKey:
- case NotificationsRecord::Key::NumberOfKeys:
- LOG_ERROR("Not a valid key");
- return false;
- }
+ if (getCurrentWindow()->getName() == app::window::name::desktop_main_window) {
+ notificationsModel->updateData(params);
+ refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
}
-
- auto ptr = getCurrentWindow();
- if (rebuildMainWindow && ptr->getName() == app::window::name::desktop_main_window) {
- ptr->rebuild();
- }
-
- return true;
}
auto ApplicationDesktop::handle(db::NotificationMessage *msg) -> bool
{
assert(msg);
-
- if (msg->interface == db::Interface::Name::Notifications && msg->type == db::Query::Type::Update) {
- return requestNotSeenNotifications(this);
- }
-
if (msg->interface == db::Interface::Name::Calllog && msg->type != db::Query::Type::Read) {
return requestUnreadCallsCount(this);
}
@@ 321,7 280,7 @@ namespace app
if (msg->getState() == EntryState::UNREAD) {
notifications.notRead.SMS = msg->getCount();
}
- return refreshMainWindow();
+ return refreshMenuWindow();
}
auto ApplicationDesktop::handle(db::query::CalllogGetCountResult *msg) -> bool
@@ 329,7 288,7 @@ namespace app
if (msg->getState() == EntryState::UNREAD) {
notifications.notRead.Calls = msg->getCount();
}
- return refreshMainWindow();
+ return refreshMenuWindow();
}
auto ApplicationDesktop::handle(cellular::StateChange *msg) -> bool
@@ 356,26 315,6 @@ namespace app
return manager::Controller::sendAction(this, manager::actions::ShowCallLog);
}
- bool ApplicationDesktop::clearCallsNotification()
- {
- LOG_DEBUG("Clear Call notifications");
- DBServiceAPI::GetQuery(this,
- db::Interface::Name::Notifications,
- std::make_unique<db::query::notifications::Clear>(NotificationsRecord::Key::Calls));
- notifications.notSeen.Calls = 0;
- return true;
- }
-
- bool ApplicationDesktop::clearMessagesNotification()
- {
- LOG_DEBUG("Clear Sms notifications");
- DBServiceAPI::GetQuery(this,
- db::Interface::Name::Notifications,
- std::make_unique<db::query::notifications::Clear>(NotificationsRecord::Key::Sms));
- notifications.notSeen.SMS = 0;
- return true;
- }
-
// Invoked during initialization
sys::ReturnCodes ApplicationDesktop::InitHandler()
{
@@ 388,7 327,6 @@ namespace app
lockPassHashChanged(
settings->getValue(settings::SystemProperties::lockPassHash, settings::SettingsScope::Global));
- requestNotSeenNotifications(this);
requestUnreadThreadsCount(this);
requestUnreadCallsCount(this);
createUserInterface();
@@ 519,8 457,8 @@ namespace app
void ApplicationDesktop::createUserInterface()
{
using namespace app::window::name;
- windowsFactory.attach(desktop_main_window, [](Application *app, const std::string &name) {
- return std::make_unique<gui::DesktopMainWindow>(app);
+ windowsFactory.attach(desktop_main_window, [this](Application *app, const std::string &name) {
+ return std::make_unique<gui::DesktopMainWindow>(app, notificationsModel);
});
windowsFactory.attach(desktop_pin_lock, [&](Application *app, const std::string newname) {
return std::make_unique<gui::PinLockWindow>(app, desktop_pin_lock);
@@ 579,7 517,7 @@ namespace app
void ApplicationDesktop::destroyUserInterface()
{}
- bool ApplicationDesktop::refreshMainWindow()
+ bool ApplicationDesktop::refreshMenuWindow()
{
if (auto menuWindow = dynamic_cast<gui::MenuWindow *>(getWindow(app::window::name::desktop_menu));
menuWindow != nullptr) {
M module-apps/application-desktop/ApplicationDesktop.hpp => module-apps/application-desktop/ApplicationDesktop.hpp +17 -12
@@ 14,6 14,7 @@
#include <endpoints/update/UpdateMuditaOS.hpp>
#include <service-desktop/ServiceDesktop.hpp>
#include <service-desktop/DesktopMessages.hpp>
+#include <notifications/NotificationListItem.hpp>
namespace cellular
{
@@ 24,7 25,12 @@ namespace db::query
{
class ThreadGetCountResult;
class CalllogGetCountResult;
-}; // namespace db::query
+} // namespace db::query
+
+namespace gui
+{
+ class NotificationsModel;
+}
namespace app
{
@@ 47,18 53,17 @@ namespace app
}
};
- Counters notSeen;
Counters notRead;
} notifications;
gui::PinLockHandler lockHandler;
- ApplicationDesktop(std::string name = name_desktop,
- std::string parent = {},
- sys::phone_modes::PhoneMode mode = sys::phone_modes::PhoneMode::Connected,
- StartInBackground startInBackground = {false});
- virtual ~ApplicationDesktop();
+ explicit ApplicationDesktop(std::string name = name_desktop,
+ std::string parent = {},
+ sys::phone_modes::PhoneMode mode = sys::phone_modes::PhoneMode::Connected,
+ StartInBackground startInBackground = {false});
+
sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override;
sys::ReturnCodes InitHandler() override;
sys::ReturnCodes DeinitHandler() override;
@@ 73,19 78,17 @@ namespace app
// done
bool handle(db::NotificationMessage *msg);
bool handle(cellular::StateChange *msg);
- auto handle(db::query::notifications::GetAllResult *msg) -> bool;
auto handle(db::query::ThreadGetCountResult *msg) -> bool;
auto handle(db::query::CalllogGetCountResult *msg) -> bool;
auto handle(sdesktop::UpdateOsMessage *msg) -> bool;
auto handle(sdesktop::developerMode::ScreenlockCheckEvent *event) -> bool;
+ void handle(manager::actions::NotificationsChangedParams *params) override;
/**
* This static method will be used to lock the phone
*/
// static bool messageLockPhone( sys::Service* sender, std::string application , const gui::InputEvent& event
//);
bool showCalls();
- bool clearCallsNotification();
- bool clearMessagesNotification();
unsigned int getLockPassHash() const noexcept
{
return lockPassHash;
@@ 101,7 104,7 @@ namespace app
void setOsUpdateVersion(const std::string &value);
private:
- bool refreshMainWindow();
+ bool refreshMenuWindow();
void activeSimChanged(std::string value);
void lockPassHashChanged(std::string value);
void handleLowBatteryNotification(manager::actions::ActionParamsPtr &&data);
@@ 110,6 113,7 @@ namespace app
void osCurrentVersionChanged(const std::string &value);
std::string osUpdateVersion{updateos::initSysVer};
std::string osCurrentVersion{updateos::initSysVer};
+ std::shared_ptr<gui::NotificationsModel> notificationsModel;
};
template <> struct ManifestTraits<ApplicationDesktop>
@@ 133,7 137,8 @@ namespace app
manager::actions::DisplayLowBatteryScreen,
manager::actions::SystemBrownout,
manager::actions::DisplayLogoAtExit,
- manager::actions::PhoneModeChanged}};
+ manager::actions::PhoneModeChanged,
+ manager::actions::NotificationsChanged}};
}
};
M module-apps/application-desktop/CMakeLists.txt => module-apps/application-desktop/CMakeLists.txt +3 -2
@@ 17,7 17,6 @@ target_sources( ${PROJECT_NAME}
"${CMAKE_CURRENT_LIST_DIR}/ApplicationDesktop.cpp"
"${CMAKE_CURRENT_LIST_DIR}/widgets/PinLock.cpp"
"${CMAKE_CURRENT_LIST_DIR}/widgets/PinLockHandler.cpp"
- "${CMAKE_CURRENT_LIST_DIR}/widgets/NotificationsBox.cpp"
"${CMAKE_CURRENT_LIST_DIR}/widgets/DesktopInputWidget.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/DesktopMainWindow.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockBaseWindow.cpp"
@@ 40,7 39,9 @@ target_sources( ${PROJECT_NAME}
"${CMAKE_CURRENT_LIST_DIR}/windows/MmiInternalMsgWindow.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/ScreenLockBaseBox.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/LockWindow.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/windows/UpdateProgress.cpp"
"${CMAKE_CURRENT_LIST_DIR}/presenter/PowerOffPresenter.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/models/ActiveNotificationsModel.cpp"
PUBLIC
"${CMAKE_CURRENT_LIST_DIR}/ApplicationDesktop.hpp"
"${CMAKE_CURRENT_LIST_DIR}/data/LockPhoneData.hpp"
@@ 50,7 51,6 @@ target_sources( ${PROJECT_NAME}
"${CMAKE_CURRENT_LIST_DIR}/widgets/PinLock.hpp"
"${CMAKE_CURRENT_LIST_DIR}/widgets/DesktopInputWidget.hpp"
"${CMAKE_CURRENT_LIST_DIR}/widgets/PinLockHandler.hpp"
- "${CMAKE_CURRENT_LIST_DIR}/widgets/NotificationsBox.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/DesktopMainWindow.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockBaseWindow.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/PinLockBox.hpp"
@@ 71,6 71,7 @@ target_sources( ${PROJECT_NAME}
"${CMAKE_CURRENT_LIST_DIR}/windows/MmiInternalMsgWindow.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/ScreenLockBaseBox.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/LockWindow.hpp"
+ "${CMAKE_CURRENT_LIST_DIR}/models/ActiveNotificationsModel.hpp"
)
target_link_libraries(${PROJECT_NAME}
M module-apps/application-desktop/data/Style.hpp => module-apps/application-desktop/data/Style.hpp +0 -14
@@ 5,20 5,6 @@
namespace style::desktop
{
-
- namespace notifications
- {
- inline constexpr auto SpanSize = 8;
- inline constexpr auto DigitSize = 16;
- inline constexpr auto IconWidth = 35;
- inline constexpr auto TextMaxWidth = 250;
-
- inline constexpr auto X = 0;
- inline constexpr auto Y = 284;
- inline constexpr auto Width = style::window_width;
-
- }; // namespace notifications
-
namespace timeLabel
{
inline constexpr auto X = 0;
A module-apps/application-desktop/models/ActiveNotificationsModel.cpp => module-apps/application-desktop/models/ActiveNotificationsModel.cpp +100 -0
@@ 0,0 1,100 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "ActiveNotificationsModel.hpp"
+#include <module-db/queries/notifications/QueryNotificationsClear.hpp>
+#include <service-appmgr/Controller.hpp>
+#include <application-messages/ApplicationMessages.hpp>
+#include <application-call/data/CallSwitchData.hpp>
+
+using namespace gui;
+
+void ActiveNotificationsModel::setParentBottomBar(const UTF8 &left, const UTF8 ¢er, const UTF8 &right)
+{
+ parent->setBottomBarText(left, BottomBar::Side::LEFT);
+ parent->setBottomBarText(center, BottomBar::Side::CENTER);
+ parent->setBottomBarText(right, BottomBar::Side::RIGHT);
+}
+auto ActiveNotificationsModel::create(const notifications::NotSeenSMSNotification *notification)
+ -> NotificationListItem *
+{
+ auto item = NotificationsModel::create(notification);
+ item->focusChangedCallback = [this](gui::Item &_item) {
+ if (_item.focus) {
+ setParentBottomBar({}, utils::translate("app_desktop_show"), utils::translate("app_desktop_clear"));
+ return true;
+ }
+ return false;
+ };
+ item->activatedCallback = [this]([[maybe_unused]] gui::Item &_item) {
+ return app::manager::Controller::sendAction(parent->getApplication(),
+ app::manager::actions::Launch,
+ std::make_unique<app::ApplicationLaunchData>(app::name_messages));
+ };
+ item->inputCallback = [this]([[maybe_unused]] Item &item, const InputEvent &inputEvent) {
+ if (inputEvent.isShortPress()) {
+ if (inputEvent.is(KeyCode::KEY_RF)) {
+ DBServiceAPI::GetQuery(
+ parent->getApplication(),
+ db::Interface::Name::Notifications,
+ std::make_unique<db::query::notifications::Clear>(NotificationsRecord::Key::Sms));
+ return true;
+ }
+ }
+ return false;
+ };
+ item->setDismissible(true);
+ return item;
+}
+auto ActiveNotificationsModel::create(const notifications::NotSeenCallNotification *notification)
+ -> NotificationListItem *
+{
+ auto item = NotificationsModel::create(notification);
+ item->activatedCallback = [this]([[maybe_unused]] gui::Item &_item) {
+ return app::manager::Controller::sendAction(parent->getApplication(), app::manager::actions::ShowCallLog);
+ };
+
+ std::function<void()> onRightFunctionalCallback = [this]() {
+ DBServiceAPI::GetQuery(parent->getApplication(),
+ db::Interface::Name::Notifications,
+ std::make_unique<db::query::notifications::Clear>(NotificationsRecord::Key::Calls));
+ };
+ std::function<void()> onKeyLeftFunctionalCallback = nullptr;
+
+ if (notification->hasRecord()) {
+ if (const auto &record = notification->getRecord(); !record->numbers.empty()) {
+ onKeyLeftFunctionalCallback = [this, number = record->numbers[0].number]() {
+ app::manager::Controller::sendAction(parent->getApplication(),
+ app::manager::actions::Dial,
+ std::make_unique<app::ExecuteCallData>(number));
+ };
+ }
+ }
+ item->inputCallback = [keyRightFunctionalCb = std::move(onRightFunctionalCallback),
+ keyLeftFunctionalCb = std::move(onKeyLeftFunctionalCallback)]([[maybe_unused]] Item &item,
+ const InputEvent &inputEvent) {
+ if (inputEvent.isShortPress()) {
+ if (inputEvent.is(KeyCode::KEY_RF)) {
+ keyRightFunctionalCb();
+ return true;
+ }
+ else if (inputEvent.is(KeyCode::KEY_LF) && keyLeftFunctionalCb != nullptr) {
+ keyLeftFunctionalCb();
+ return true;
+ }
+ }
+ return false;
+ };
+
+ item->focusChangedCallback = [this, canCall = notification->hasRecord()](gui::Item &_item) {
+ if (_item.focus) {
+ UTF8 bottomBarLeftText = canCall ? UTF8{utils::translate("common_call")} : UTF8{};
+ setParentBottomBar(
+ bottomBarLeftText, utils::translate("app_desktop_show"), utils::translate("app_desktop_clear"));
+ }
+ return true;
+ };
+
+ item->setDismissible(true);
+ return item;
+}
A module-apps/application-desktop/models/ActiveNotificationsModel.hpp => module-apps/application-desktop/models/ActiveNotificationsModel.hpp +16 -0
@@ 0,0 1,16 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <notifications/NotificationsModel.hpp>
+
+namespace gui
+{
+ class ActiveNotificationsModel : public gui::NotificationsModel
+ {
+ void setParentBottomBar(const UTF8 &left, const UTF8 ¢er, const UTF8 &right);
+ auto create(const notifications::NotSeenSMSNotification *notification) -> NotificationListItem * override;
+ auto create(const notifications::NotSeenCallNotification *notification) -> NotificationListItem * override;
+ };
+} // namespace gui
D module-apps/application-desktop/widgets/NotificationsBox.cpp => module-apps/application-desktop/widgets/NotificationsBox.cpp +0 -204
@@ 1,204 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "NotificationsBox.hpp"
-
-#include "application-desktop/data/Style.hpp"
-
-#include "TextFixedSize.hpp"
-#include "RichTextParser.hpp"
-#include "FontManager.hpp"
-
-using namespace gui;
-using namespace style::desktop;
-
-NotificationsBox::NotificationsBox(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
- : VBox(parent, x, y, w, h)
-{
- this->setAlignment(Alignment(gui::Alignment::Horizontal::Center));
- this->setPenWidth(style::window::default_border_no_focus_w);
- this->setPenFocusWidth(style::window::default_border_no_focus_w);
-
- auto getNextNotification = [this]() -> Item * {
- auto focusedItem = getFocusItem();
- if (focusedItem == nullptr) {
- return nullptr;
- }
- auto nextItem = focusedItem->getNavigationItem(NavigationDirection::UP);
-
- if (nextItem == nullptr) {
- nextItem = focusedItem->getNavigationItem(NavigationDirection::DOWN);
- }
- return nextItem;
- };
-
- auto setNextFocusedItemAfterErase = [this](Item *item) -> bool {
- if (item == nullptr) {
- setFocus(false);
- }
- else {
- item->clearNavigationItem(NavigationDirection::DOWN);
- item->clearNavigationItem(NavigationDirection::UP);
- setNavigation();
- setFocusItem(item);
- }
- return true;
- };
-
- inputCallback = [this, setNextFocusedItemAfterErase, getNextNotification](Item &, const InputEvent &event) -> bool {
- if (event.isShortPress() && event.is(KeyCode::KEY_RF)) {
- LOG_DEBUG("Removing single notification");
- auto ptr = getFocusItem();
- if (ptr == nullptr || focusItem == this) {
- return false;
- }
- auto nextItem = getNextNotification();
- ptr->inputCallback(*this, event);
- erase(ptr);
- return setNextFocusedItemAfterErase(nextItem);
- }
- return false;
- };
-}
-
-namespace
-{
- auto buildImageInactive(const UTF8 &img) -> gui::Image *
- {
- auto thumbnail = new gui::Image(img);
- thumbnail->activeItem = false;
- return thumbnail;
- }
-
- auto buildNotificationIcon(UTF8 icon) -> gui::Image *
- {
- auto thumbnail = buildImageInactive(icon);
- thumbnail->setMinimumWidth(notifications::IconWidth);
- thumbnail->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
- thumbnail->setMargins(
- gui::Margins(style::window::default_left_margin, 0, style::window::default_right_margin, 0));
- return thumbnail;
- }
-
- auto buildNotificationNameLabel(const UTF8 &name, uint32_t width) -> gui::TextFixedSize *
- {
- auto text = new gui::TextFixedSize(
- nullptr, 0, 0, style::desktop::notifications::TextMaxWidth, style::window::label::default_h);
- text->setMaximumSize(width, Axis::X);
-
- TextFormat format(FontManager::getInstance().getFont(style::window::font::medium));
- text::RichTextParser rtParser;
- auto parsedText = rtParser.parse(name, &format);
-
- text->setText(std::move(parsedText));
- text->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
- text->setPenWidth(style::window::default_border_no_focus_w);
- text->setUnderline(false);
- text->activeItem = false;
- return text;
- }
-
- constexpr auto maxNotificationValue = "99+";
-
- auto buildNotificationCountText(const UTF8 &indicator) -> gui::Text *
- {
- auto number = new gui::Text();
- if (indicator.length() > 2) {
- number->setText(maxNotificationValue);
- }
- else {
- number->setText(indicator);
- }
-
- number->setMinimumWidth(number->getText().length() * notifications::DigitSize);
- number->setFont(style::window::font::mediumbold);
- number->setPenWidth(style::window::default_border_no_focus_w);
- number->setMargins(gui::Margins(0, 0, style::window::default_right_margin, 0));
- number->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
- number->activeItem = false;
- return number;
- }
-
- void setNotificationHboxLayoutProperties(gui::HBox *hbox)
- {
- hbox->setAlignment(Alignment(gui::Alignment::Vertical::Center));
- hbox->setMargins(gui::Margins(0, 0, 0, 10));
- hbox->setPenWidth(style::window::default_border_no_focus_w);
- hbox->setPenFocusWidth(style::window::default_border_focus_w);
- hbox->setEdges(RectangleEdge::Bottom | RectangleEdge::Top);
- }
-
-} // namespace
-
-auto NotificationsBox::addNotification(const UTF8 &icon,
- const UTF8 &name,
- const UTF8 &indicator,
- std::function<bool()> showCallback,
- std::function<bool()> clearCallback,
- std::function<void(bool)> onFocus) -> bool
-{
- // 1. create hbox for all elements
- auto el = new gui::HBox(nullptr, 0, 0, style::window::default_body_width, style::window::label::default_h);
-
- // 2. Add all elements to hbox layout
- el->addWidget(buildNotificationIcon(icon));
-
- el->addWidget(buildNotificationNameLabel(name, el->area().w));
- el->addWidget(buildImageInactive("dot_12px_hard_alpha_W_G"));
- el->addWidget(buildNotificationCountText(indicator));
-
- // 3. Set hbox layout properties
- setNotificationHboxLayoutProperties(el);
-
- el->focusChangedCallback = [el, onFocus](Item &) -> bool {
- onFocus(el->focus);
- return true;
- };
- el->activatedCallback = [showCallback](Item &) { return showCallback(); };
- el->inputCallback = [showCallback, clearCallback, this](Item &, const InputEvent &event) -> bool {
- if (event.isShortPress() && event.is(KeyCode::KEY_RF) && clearCallback) {
- return clearCallback();
- }
- return false;
- };
-
- this->addWidget(el);
- return el->visible;
-}
-
-auto NotificationsBox::addNotification(const UTF8 &icon, const UTF8 &name) -> bool
-{
- auto el = new gui::HBox(this, 0, 0, style::window::default_body_width, style::window::label::default_h);
-
- el->addWidget(buildNotificationIcon(icon));
- el->addWidget(buildNotificationNameLabel(name, el->area().w));
- setNotificationHboxLayoutProperties(el);
-
- return el->visible;
-}
-
-bool NotificationsBox::onInput(const InputEvent &inputEvent)
-{
-
- if (inputEvent.isShortPress() && (inputEvent.is(KeyCode::KEY_UP) || inputEvent.is(KeyCode::KEY_DOWN))) {
- auto handled = handleNavigation(inputEvent);
- if (!handled) {
- setFocus(false);
- }
- return true;
- }
- return VBox::onInput(inputEvent);
-}
-
-bool NotificationsBox::clearAll(const InputEvent &event)
-{
- while (!children.empty()) {
- inputCallback(*this, event);
- }
- return true;
-}
-
-void NotificationsBox::navigateToBottom()
-{
- setFocusItem(children.back());
-}
D module-apps/application-desktop/widgets/NotificationsBox.hpp => module-apps/application-desktop/widgets/NotificationsBox.hpp +0 -30
@@ 1,30 0,0 @@
-// 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 "BoxLayout.hpp"
-#include "Icon.hpp"
-
-namespace gui
-{
- class NotificationsBox : public VBox
- {
- public:
- NotificationsBox(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
-
- auto addNotification(const UTF8 &icon,
- const UTF8 &name,
- const UTF8 &indicator,
- std::function<bool()> showCallback,
- std::function<bool()> clearCallback,
- std::function<void(bool)> onFocus) -> bool;
-
- auto addNotification(const UTF8 &icon, const UTF8 &name) -> bool;
-
- bool onInput(const InputEvent &inputEvent) override;
- bool clearAll(const InputEvent &event);
-
- void navigateToBottom();
- };
-} // namespace gui
M module-apps/application-desktop/windows/DesktopMainWindow.cpp => module-apps/application-desktop/windows/DesktopMainWindow.cpp +73 -91
@@ 5,13 5,11 @@
#include "Alignment.hpp"
#include "BottomBar.hpp"
-#include "Common.hpp"
#include "DesktopMainWindow.hpp"
#include "GuiTimer.hpp"
#include "application-desktop/ApplicationDesktop.hpp"
#include "application-desktop/data/LockPhoneData.hpp"
#include "application-desktop/data/Style.hpp"
-#include "application-desktop/widgets/NotificationsBox.hpp"
#include "application-messages/ApplicationMessages.hpp"
#include "gui/widgets/Image.hpp"
#include <service-appmgr/Controller.hpp>
@@ 21,7 19,6 @@
#include <i18n/i18n.hpp>
#include "log/log.hpp"
-#include <application-settings-new/ApplicationSettings.hpp>
#include <application-settings/ApplicationSettings.hpp>
#include <cassert>
#include <time/time_conversion.hpp>
@@ 35,7 32,8 @@ namespace gui
bottomBar->setActive(BottomBar::Side::CENTER, true);
- using namespace style::desktop;
+ namespace timeLabel = style::desktop::timeLabel;
+ namespace dayLabel = style::desktop::dayLabel;
time = new gui::Label(this, timeLabel::X, timeLabel::Y, timeLabel::Width, timeLabel::Height);
time->setFilled(false);
@@ 49,11 47,31 @@ namespace gui
dayText->setFont(style::window::font::biglight);
dayText->setAlignment(Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Top));
- activatedCallback = [this](Item &) {
+ activatedCallback = [this]([[maybe_unused]] Item &item) {
application->switchWindow(app::window::name::desktop_menu);
return true;
};
+ notificationsList = new ListView(this,
+ style::notifications::model::x,
+ style::notifications::model::y,
+ style::notifications::model::w,
+ style::notifications::model::h,
+ notificationsModel,
+ listview::ScrollBarType::Fixed);
+ notificationsList->emptyListCallback = [this]() {
+ setFocusItem(nullptr);
+ setVisibleState();
+ };
+ notificationsList->notEmptyListCallback = [this]() {
+ if (focusItem == nullptr) {
+ setVisibleState();
+ }
+ };
+
+ applyToTopBar(
+ [this](top_bar::Configuration configuration) { return configureTopBar(std::move(configuration)); });
+
setVisibleState();
}
@@ 67,7 85,6 @@ namespace gui
{
time = nullptr;
dayText = nullptr;
- notifications = nullptr;
}
top_bar::Configuration DesktopMainWindow::configureTopBar(top_bar::Configuration appConfiguration)
@@ 80,8 97,10 @@ namespace gui
return appConfiguration;
}
- DesktopMainWindow::DesktopMainWindow(app::Application *app) : AppWindow(app, app::window::name::desktop_main_window)
+ DesktopMainWindow::DesktopMainWindow(app::Application *app, std::shared_ptr<NotificationsModel> model)
+ : AppWindow(app, app::window::name::desktop_main_window), notificationsModel(std::move(model))
{
+ notificationsModel->setParentWindow(this);
osUpdateVer = getAppDesktop()->getOsUpdateVersion();
osCurrentVer = getAppDesktop()->getOsCurrentVersion();
@@ 90,13 109,15 @@ namespace gui
preBuildDrawListHook = [this](std::list<Command> &cmd) { updateTime(); };
}
- void DesktopMainWindow::setVisibleState()
+ DesktopMainWindow::~DesktopMainWindow()
{
- auto app = getAppDesktop();
- applyToTopBar(
- [this](top_bar::Configuration configuration) { return configureTopBar(std::move(configuration)); });
+ notificationsModel->clearAll();
+ notificationsModel->list = nullptr;
+ }
- if (app->lockHandler.isScreenLocked()) {
+ void DesktopMainWindow::setVisibleState()
+ {
+ if (auto app = getAppDesktop(); app->lockHandler.isScreenLocked()) {
bottomBar->setText(BottomBar::Side::CENTER, utils::translate("app_desktop_unlock"));
bottomBar->setActive(BottomBar::Side::RIGHT, false);
bottomBar->setText(
@@ 104,15 125,11 @@ namespace gui
inputCallback = nullptr;
setFocusItem(nullptr);
- buildNotifications(app);
application->bus.sendUnicast(std::make_shared<TimersProcessingStopMessage>(), service::name::service_time);
}
else {
- if (!buildNotifications(app)) {
- LOG_ERROR("Couldn't fit in all notifications");
- }
- setActiveState(app);
+ setActiveState();
if (osUpdateVer == osCurrentVer && osUpdateVer != updateos::initSysVer &&
osCurrentVer != updateos::initSysVer) {
@@ 133,6 150,7 @@ namespace gui
void DesktopMainWindow::onBeforeShow(ShowMode mode, SwitchData *data)
{
+ app::manager::Controller::requestNotifications(application);
setVisibleState();
}
@@ 161,6 179,12 @@ namespace gui
return AppWindow::onInput(inputEvent);
}
+ namespace
+ {
+ constexpr auto pageFirstNotificationIdx = 0;
+ constexpr auto pageLastNotificationIdx = style::notifications::model::maxNotificationsPerPage - 1;
+ } // namespace
+
bool DesktopMainWindow::processShortPressEventOnUnlocked(const InputEvent &inputEvent)
{
auto code = translator.handle(inputEvent.key, InputMode({InputMode::phone}).get());
@@ 170,17 194,30 @@ namespace gui
return app::manager::Controller::sendAction(
application, app::manager::actions::Dial, std::make_unique<app::EnterNumberData>(number));
}
- else if (inputEvent.is(KeyCode::KEY_UP) && focusItem == nullptr) {
- setFocusItem(notifications);
- notifications->navigateToBottom();
+ else if (const auto notificationsNotFocused = (focusItem == nullptr);
+ notificationsNotFocused && !notificationsModel->isEmpty()) {
+ if (inputEvent.is(KeyCode::KEY_UP)) {
+ notificationsList->rebuildList(listview::RebuildType::OnPageElement, pageLastNotificationIdx);
+ setFocusItem(notificationsList);
+ return true;
+ }
+ else if (inputEvent.is(KeyCode::KEY_DOWN)) {
+ notificationsList->rebuildList(listview::RebuildType::OnPageElement, pageFirstNotificationIdx);
+ setFocusItem(notificationsList);
+ return true;
+ }
+ }
+ // check if any of the lower inheritance onInput methods catch the event
+ if (AppWindow::onInput(inputEvent)) {
return true;
}
- else if (inputEvent.is(KeyCode::KEY_DOWN) && focusItem == nullptr) {
- setFocusItem(notifications);
+ if ((inputEvent.is(KeyCode::KEY_UP) || inputEvent.is(KeyCode::KEY_DOWN)) && focusItem != nullptr) {
+ LOG_DEBUG("Notification box lost focus");
+ setFocusItem(nullptr);
+ setActiveState();
return true;
}
- // check if any of the lower inheritance onInput methods catch the event
- return AppWindow::onInput(inputEvent);
+ return false;
}
bool DesktopMainWindow::processShortPressEventOnLocked(const InputEvent &inputEvent)
@@ 232,79 269,24 @@ namespace gui
buildInterface();
}
- auto DesktopMainWindow::buildNotifications(app::ApplicationDesktop *app) -> bool
- {
- erase(notifications);
- using namespace style::desktop;
- notifications = new NotificationsBox(this,
- notifications::X,
- notifications::Y,
- notifications::Width,
- bottomBar->widgetArea.pos(Axis::Y) - notifications::Y);
-
- addWidget(notifications);
- if (!notifications->visible) {
- LOG_ERROR("Can't fit notifications box!");
- return false;
- }
-
- auto onNotificationFocus = [this](bool isFocused) -> void {
- bottomBar->setText(BottomBar::Side::CENTER, utils::translate("app_desktop_show"), isFocused);
- bottomBar->setText(BottomBar::Side::RIGHT, utils::translate("app_desktop_clear"), isFocused);
- bottomBar->setActive(BottomBar::Side::LEFT, !isFocused);
- };
-
- if (app->notifications.notSeen.Calls > 0) {
- notifications->addNotification(
- "phone",
- utils::translate("app_desktop_missed_calls"),
- std::to_string(app->notifications.notSeen.Calls),
- [app]() -> bool { return app->showCalls(); },
- [app]() -> bool { return app->clearCallsNotification(); },
- onNotificationFocus);
- }
- if (app->notifications.notSeen.SMS > 0) {
- notifications->addNotification(
- "mail",
- utils::translate("app_desktop_unread_messages"),
- std::to_string(app->notifications.notSeen.SMS),
- [this]() -> bool {
- return app::manager::Controller::sendAction(
- application,
- app::manager::actions::Launch,
- std::make_unique<app::ApplicationLaunchData>(app::name_messages));
- },
- [app, this]() -> bool { return app->clearMessagesNotification(); },
- onNotificationFocus);
- }
-
- notifications->focusChangedCallback = [this, app](Item &) -> bool {
- if (notifications->focus == false) {
- LOG_DEBUG("Notification box lost focus");
- setFocusItem(nullptr);
- setActiveState(app);
- return true;
- }
- return false;
- };
-
- return true;
- }
- auto DesktopMainWindow::setActiveState(app::ApplicationDesktop *app) -> bool
+ auto DesktopMainWindow::setActiveState() -> bool
{
bottomBar->setText(BottomBar::Side::CENTER, utils::translate("app_desktop_menu"));
bottomBar->setText(BottomBar::Side::LEFT, utils::translate("app_desktop_calls"));
- auto hasNotifications = !app->notifications.notSeen.areEmpty();
- bottomBar->setText(BottomBar::Side::RIGHT, utils::translate("app_desktop_clear_all"), hasNotifications);
-
- inputCallback = [this, app, hasNotifications](Item &, const InputEvent &inputEvent) -> bool {
- if (!inputEvent.isShortPress()) {
+ const auto hasDismissibleNotification = notificationsModel->hasDismissibleNotification();
+ bottomBar->setText(
+ BottomBar::Side::RIGHT, utils::translate("app_desktop_clear_all"), hasDismissibleNotification);
+
+ auto app = getAppDesktop();
+ inputCallback = [this, app, hasDismissibleNotification]([[maybe_unused]] Item &item,
+ const InputEvent &inputEvent) -> bool {
+ if (!inputEvent.isShortPress() || notificationsList->focus) {
return false;
}
- if (inputEvent.is(KeyCode::KEY_RF) && hasNotifications) {
+ if (inputEvent.is(KeyCode::KEY_RF) && hasDismissibleNotification) {
LOG_DEBUG("KEY_RF pressed to clear all notifications");
- setFocusItem(notifications);
- return notifications->clearAll(inputEvent);
+ notificationsModel->dismissAll(inputEvent);
+ return true;
}
if (inputEvent.is(gui::KeyCode::KEY_LF)) {
LOG_DEBUG("KEY_LF pressed to navigate to calls");
M module-apps/application-desktop/windows/DesktopMainWindow.hpp => module-apps/application-desktop/windows/DesktopMainWindow.hpp +8 -6
@@ 8,6 8,8 @@
#include "gui/widgets/Window.hpp"
#include "Translator.hpp"
+#include <notifications/NotificationsModel.hpp>
+#include <ListView.hpp>
namespace app
{
@@ 16,14 18,14 @@ namespace app
namespace gui
{
- class NotificationsBox;
-
class DesktopMainWindow : public AppWindow
{
protected:
gui::Label *time = nullptr;
gui::Label *dayText = nullptr;
- gui::NotificationsBox *notifications = nullptr;
+
+ gui::ListView *notificationsList = nullptr;
+ std::shared_ptr<gui::NotificationsModel> notificationsModel = nullptr;
/// Timed enter value cache, could be templated to any value really
class EnterCache
@@ 64,15 66,15 @@ namespace gui
// method hides or show widgets and sets bars according to provided state
void setVisibleState();
- auto buildNotifications(app::ApplicationDesktop *app) -> bool;
- auto setActiveState(app::ApplicationDesktop *app) -> bool;
+ auto setActiveState() -> bool;
bool processLongPressEvent(const InputEvent &inputEvent);
bool processShortPressEventOnUnlocked(const InputEvent &inputEvent);
bool processShortPressEventOnLocked(const InputEvent &inputEvent);
app::ApplicationDesktop *getAppDesktop() const;
public:
- DesktopMainWindow(app::Application *app);
+ DesktopMainWindow(app::Application *app, std::shared_ptr<NotificationsModel> model);
+ ~DesktopMainWindow();
// virtual methods gui::Window
bool onInput(const InputEvent &inputEvent) override;
A module-apps/notifications/NotificationData.cpp => module-apps/notifications/NotificationData.cpp +64 -0
@@ 0,0 1,64 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "NotificationData.hpp"
+
+uint32_t notifications::Notification::priorityPool = 0;
+
+using namespace notifications;
+
+Notification::Notification(NotificationType type, NotificationPriority priorityType) : type{type}
+{
+ switch (priorityType) {
+ case NotificationPriority::Next:
+ if (priorityPool == highestPriority) {
+ priorityPool = 0;
+ }
+ priority = ++priorityPool;
+ break;
+ case NotificationPriority::Highest:
+ priority = highestPriority;
+ break;
+ case NotificationPriority::Lowest:
+ priority = lowestPriority;
+ break;
+ }
+}
+
+auto Notification::getType() const noexcept -> NotificationType
+{
+ return type;
+}
+
+auto Notification::getPriority() const noexcept -> uint32_t
+{
+ return priority;
+}
+
+NotSeenSMSNotification::NotSeenSMSNotification(unsigned value)
+ : Notification(NotificationType::NotSeenSms), value{value}
+{}
+
+auto NotSeenSMSNotification::getValue() const noexcept -> unsigned
+{
+ return value;
+}
+
+NotSeenCallNotification::NotSeenCallNotification(unsigned value, std::unique_ptr<ContactRecord> record)
+ : Notification(NotificationType::NotSeenCall), value{value}, record{std::move(record)}
+{}
+
+bool NotSeenCallNotification::hasRecord() const noexcept
+{
+ return record != nullptr;
+}
+
+auto NotSeenCallNotification::getRecord() const noexcept -> const std::unique_ptr<ContactRecord> &
+{
+ return record;
+}
+
+auto NotSeenCallNotification::getValue() const noexcept -> unsigned
+{
+ return value;
+}
A module-apps/notifications/NotificationData.hpp => module-apps/notifications/NotificationData.hpp +68 -0
@@ 0,0 1,68 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <limits>
+#include <list>
+
+#include <ContactRecord.hpp>
+
+namespace notifications
+{
+ enum class NotificationType
+ {
+ Unknown,
+ NotSeenSms,
+ NotSeenCall,
+ };
+
+ enum class NotificationPriority
+ {
+ Next,
+ Highest,
+ Lowest
+ };
+
+ class Notification
+ {
+ static constexpr auto highestPriority = std::numeric_limits<uint32_t>::max();
+ static constexpr auto lowestPriority = 0;
+ static uint32_t priorityPool;
+
+ NotificationType type;
+ uint32_t priority;
+
+ protected:
+ explicit Notification(NotificationType type, NotificationPriority priorityType = NotificationPriority::Next);
+
+ public:
+ [[nodiscard]] auto getType() const noexcept -> NotificationType;
+ [[nodiscard]] auto getPriority() const noexcept -> uint32_t;
+
+ virtual ~Notification() = default;
+ };
+
+ class NotSeenSMSNotification : public Notification
+ {
+ unsigned value = 0;
+
+ public:
+ explicit NotSeenSMSNotification(unsigned value);
+ [[nodiscard]] auto getValue() const noexcept -> unsigned;
+ };
+
+ class NotSeenCallNotification : public Notification
+ {
+ unsigned value = 0;
+ std::unique_ptr<ContactRecord> record;
+
+ public:
+ explicit NotSeenCallNotification(unsigned value, std::unique_ptr<ContactRecord> record = nullptr);
+
+ [[nodiscard]] bool hasRecord() const noexcept;
+ [[nodiscard]] auto getRecord() const noexcept -> const std::unique_ptr<ContactRecord> &;
+ [[nodiscard]] auto getValue() const noexcept -> unsigned;
+ };
+
+} // namespace notifications
A module-apps/notifications/NotificationListItem.cpp => module-apps/notifications/NotificationListItem.cpp +138 -0
@@ 0,0 1,138 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "NotificationListItem.hpp"
+
+#include "TextFixedSize.hpp"
+#include "RichTextParser.hpp"
+#include "FontManager.hpp"
+#include "Image.hpp"
+
+#include <widgets/Style.hpp>
+#include <map>
+
+using namespace gui;
+// using namespace style::desktop;
+
+namespace
+{
+ auto buildImageInactive(const UTF8 &img) -> gui::Image *
+ {
+ auto thumbnail = new gui::Image(img);
+ thumbnail->activeItem = false;
+ return thumbnail;
+ }
+
+ auto buildNotificationIcon(const UTF8 &icon) -> gui::Image *
+ {
+ auto thumbnail = buildImageInactive(icon);
+ thumbnail->setMinimumWidth(style::notifications::iconWidth);
+ thumbnail->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
+ thumbnail->setMargins(
+ gui::Margins(style::window::default_left_margin, 0, style::window::default_right_margin, 0));
+ return thumbnail;
+ }
+
+ auto buildNotificationNameLabel(uint32_t width) -> gui::TextFixedSize *
+ {
+ auto text =
+ new gui::TextFixedSize(nullptr, 0, 0, style::notifications::textMaxWidth, style::notifications::itemHeight);
+ text->setMaximumSize(width, Axis::X);
+
+ text->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
+ text->setPenWidth(style::window::default_border_no_focus_w);
+ text->setUnderline(false);
+ text->setFont(style::window::font::medium);
+ text->activeItem = false;
+ return text;
+ }
+
+ void setNotificationHboxLayoutProperties(gui::HBox *hbox)
+ {
+ hbox->setAlignment(Alignment(gui::Alignment::Vertical::Center));
+ hbox->setMargins(gui::Margins(0, 0, 0, 10));
+ hbox->setPenWidth(style::window::default_border_no_focus_w);
+ hbox->setPenFocusWidth(style::window::default_border_focus_w);
+ hbox->setEdges(RectangleEdge::None);
+ hbox->setMaximumSize(style::window::default_body_width, style::notifications::itemHeight);
+ }
+
+ constexpr auto maxNotificationValue = "99+";
+ constexpr auto singleNotification = "1";
+
+ auto buildNotificationCountText(const UTF8 &indicator) -> gui::Text *
+ {
+ auto number = new gui::Text();
+ if (indicator.length() > 2) {
+ number->setText(maxNotificationValue);
+ }
+ else if (indicator == singleNotification) {
+ number->clear();
+ }
+ else {
+ number->setText(indicator);
+ }
+
+ number->setMinimumWidth(number->getText().length() * style::notifications::digitSize);
+ number->setFont(style::window::font::mediumbold);
+ number->setPenWidth(style::window::default_border_no_focus_w);
+ number->setMargins(gui::Margins(0, 0, style::window::default_right_margin, 0));
+ number->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
+ number->activeItem = false;
+ return number;
+ }
+
+ std::map<notifications::NotificationType, UTF8> typeToIcon{
+ {notifications::NotificationType::Unknown, "phone"},
+ {notifications::NotificationType::NotSeenSms, "mail"},
+ {notifications::NotificationType::NotSeenCall, "phone"},
+ };
+} // namespace
+
+NotificationListItem::NotificationListItem(NotificationType type) : type{type}
+{
+ this->setMinimumHeight(style::notifications::itemHeight);
+ this->setMaximumWidth(style::window::default_body_width);
+
+ box = new gui::HBox(this, 0, 0, style::window::default_body_width, style::notifications::itemHeight);
+ box->addWidget(buildNotificationIcon(typeToIcon[type]));
+ text = buildNotificationNameLabel(box->area().w);
+ box->addWidget(text);
+
+ setNotificationHboxLayoutProperties(box);
+}
+
+void NotificationListItem::setName(const UTF8 &name, bool isRich, gui::text::RichTextParser::TokenMap &&tokens)
+{
+ if (isRich) {
+ TextFormat format(FontManager::getInstance().getFont(style::window::font::medium));
+ text::RichTextParser rtParser;
+ auto parsedText = rtParser.parse(name, &format, std::move(tokens));
+ text->setText(std::move(parsedText));
+ }
+ else {
+ text->setText(name);
+ }
+}
+
+void NotificationListItem::setDismissible(bool isDismissible) noexcept
+{
+ dismissible = isDismissible;
+}
+
+bool NotificationListItem::isDismissible() const noexcept
+{
+ return dismissible;
+}
+
+notifications::NotificationType NotificationListItem::getType() const noexcept
+{
+ return type;
+}
+
+NotificationWithEventCounter::NotificationWithEventCounter(notifications::NotificationType type, const UTF8 &indicator)
+ : NotificationListItem(type)
+{
+ box->addWidget(buildImageInactive("dot_12px_hard_alpha_W_G"));
+ box->addWidget(buildNotificationCountText(indicator));
+}
A module-apps/notifications/NotificationListItem.hpp => module-apps/notifications/NotificationListItem.hpp +43 -0
@@ 0,0 1,43 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <ListItem.hpp>
+#include <BoxLayout.hpp>
+#include <Text.hpp>
+#include <RichTextParser.hpp>
+
+#include "NotificationData.hpp"
+
+namespace gui
+{
+
+ class TextFixedSize;
+
+ class NotificationListItem : public ListItem
+ {
+ using NotificationType = notifications::NotificationType;
+ const NotificationType type = NotificationType::Unknown;
+ bool dismissible = false;
+
+ protected:
+ gui::HBox *box = nullptr;
+ gui::TextFixedSize *text = nullptr;
+
+ public:
+ explicit NotificationListItem(NotificationType type);
+
+ [[nodiscard]] bool isDismissible() const noexcept;
+ [[nodiscard]] NotificationType getType() const noexcept;
+ void setName(const UTF8 &name, bool isRich = false, gui::text::RichTextParser::TokenMap &&tokens = {});
+ void setDismissible(bool isDismissible) noexcept;
+ };
+
+ class NotificationWithEventCounter : public NotificationListItem
+ {
+ public:
+ NotificationWithEventCounter(notifications::NotificationType type, const UTF8 &indicator);
+ };
+
+} // namespace gui
A module-apps/notifications/NotificationProvider.cpp => module-apps/notifications/NotificationProvider.cpp +101 -0
@@ 0,0 1,101 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "NotificationProvider.hpp"
+#include <Service/Service.hpp>
+#include <module-db/queries/notifications/QueryNotificationsGetAll.hpp>
+#include <service-appmgr/Controller.hpp>
+#include <service-appmgr/data/NotificationsChangedActionsParams.hpp>
+#include <service-db/DBNotificationMessage.hpp>
+
+using namespace notifications;
+
+NotificationProvider::NotificationProvider(sys::Service *ownerService) : ownerService{ownerService}
+{}
+
+template <NotificationType type, typename T> bool NotificationProvider::handleNotSeenWithCounter(unsigned int value)
+{
+ if (notifications.count(type) > 0) {
+ if (value == 0) {
+ notifications.erase(type);
+ return true;
+ }
+ if (auto notification = static_cast<T *>(notifications[type].get()); value > notification->getValue()) {
+ notifications[type] = std::make_shared<T>(value);
+ return true;
+ }
+ }
+ else if (value > 0) {
+ notifications[type] = std::make_shared<T>(value);
+ return true;
+ }
+ return false;
+}
+
+void NotificationProvider::handle(db::query::notifications::GetAllResult *msg)
+{
+ assert(msg);
+ auto records = *msg->getResult();
+
+ bool notificationsChanged = false;
+ for (auto record : records) {
+ switch (record.key) {
+ case NotificationsRecord::Key::Calls:
+ notificationsChanged |=
+ handleNotSeenWithCounter<NotificationType::NotSeenCall, NotSeenCallNotification>(record.value);
+ break;
+ case NotificationsRecord::Key::Sms:
+ notificationsChanged |=
+ handleNotSeenWithCounter<NotificationType::NotSeenSms, NotSeenSMSNotification>(record.value);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (notificationsChanged) {
+ send();
+ }
+}
+
+void NotificationProvider::handle(db::NotificationMessage *msg)
+{
+ if (msg->interface == db::Interface::Name::Notifications && msg->type == db::Query::Type::Update) {
+ requestNotSeenNotifications();
+ }
+}
+
+void NotificationProvider::requestNotSeenNotifications()
+{
+ DBServiceAPI::GetQuery(
+ ownerService, db::Interface::Name::Notifications, std::make_unique<db::query::notifications::GetAll>());
+}
+
+namespace
+{
+ using mapType = NotificationProvider::Notifications;
+ using returnType = std::shared_ptr<Notification>;
+ struct get_second : public std::unary_function<mapType::value_type, returnType>
+ {
+ returnType operator()(const mapType::value_type &value) const
+ {
+ return value.second;
+ }
+ };
+} // namespace
+
+void NotificationProvider::send()
+{
+ std::list<std::shared_ptr<const Notification>> toSendNotifications;
+ transform(notifications.begin(), notifications.end(), back_inserter(toSendNotifications), get_second());
+
+ toSendNotifications.sort(
+ [](const std::shared_ptr<const Notification> &lhs, const std::shared_ptr<const Notification> &rhs) {
+ return (lhs->getPriority() > rhs->getPriority());
+ });
+
+ app::manager::Controller::sendAction(
+ ownerService,
+ app::manager::actions::NotificationsChanged,
+ std::make_unique<app::manager::actions::NotificationsChangedParams>(std::move(toSendNotifications)));
+}
A module-apps/notifications/NotificationProvider.hpp => module-apps/notifications/NotificationProvider.hpp +44 -0
@@ 0,0 1,44 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "NotificationData.hpp"
+
+namespace sys
+{
+ class Service;
+}
+
+namespace db
+{
+ class NotificationMessage;
+ namespace query::notifications
+ {
+ class GetAllResult;
+ }
+} // namespace db
+
+namespace notifications
+{
+
+ class NotificationProvider
+ {
+ template <NotificationType type, typename T> bool handleNotSeenWithCounter(unsigned int value);
+
+ public:
+ explicit NotificationProvider(sys::Service *ownerService);
+
+ void handle(db::query::notifications::GetAllResult *msg);
+ void handle(db::NotificationMessage *msg);
+ void requestNotSeenNotifications();
+ void send();
+
+ using Notifications = std::map<NotificationType, std::shared_ptr<Notification>>;
+
+ private:
+ sys::Service *ownerService;
+ Notifications notifications;
+ };
+
+} // namespace notifications
A module-apps/notifications/NotificationsModel.cpp => module-apps/notifications/NotificationsModel.cpp +114 -0
@@ 0,0 1,114 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "NotificationsModel.hpp"
+#include <ListView.hpp>
+
+using namespace gui;
+
+unsigned int NotificationsModel::requestRecordsCount()
+{
+ return internalData.size();
+}
+
+gui::ListItem *NotificationsModel::getItem(gui::Order order)
+{
+ return getRecord(order);
+}
+
+void NotificationsModel::requestRecords(uint32_t offset, uint32_t limit)
+{
+ setupModel(offset, limit);
+ list->onProviderDataUpdate();
+}
+
+unsigned int NotificationsModel::getMinimalItemHeight() const
+{
+ return style::notifications::itemHeight;
+}
+
+bool NotificationsModel::hasDismissibleNotification() const noexcept
+{
+ for (const auto notification : internalData) {
+ if (notification->isDismissible()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void NotificationsModel::dismissAll(const InputEvent &event)
+{
+ for (auto it = std::begin(internalData); it != std::end(internalData); it++) {
+ if (auto item = *it; item->isDismissible()) {
+ item->onInput(event);
+ }
+ }
+}
+
+bool NotificationsModel::isEmpty() const noexcept
+{
+ return internalData.empty();
+}
+
+auto NotificationsModel::create(const notifications::NotSeenSMSNotification *notification) -> NotificationListItem *
+{
+ auto item = new NotificationWithEventCounter(notifications::NotificationType::NotSeenSms,
+ utils::to_string(notification->getValue()));
+ item->setName(utils::translate("app_desktop_unread_messages"), true);
+ item->deleteByList = false;
+ return item;
+}
+auto NotificationsModel::create(const notifications::NotSeenCallNotification *notification) -> NotificationListItem *
+{
+ auto item = new NotificationWithEventCounter(notifications::NotificationType::NotSeenCall,
+ utils::to_string(notification->getValue()));
+ if (notification->hasRecord()) {
+ const auto &record = notification->getRecord();
+ item->setName(record->getFormattedName());
+ }
+ else {
+ item->setName(utils::translate("app_desktop_missed_calls"), true);
+ }
+ item->deleteByList = false;
+ return item;
+}
+
+void NotificationsModel::updateData(app::manager::actions::NotificationsChangedParams *params)
+{
+ if (list == nullptr) {
+ LOG_ERROR("ListView object not provided");
+ }
+
+ list->prepareRebuildCallback = [this, toRemove = std::move(internalData)] {
+ list->clear();
+ for (auto item : toRemove) {
+ delete item;
+ }
+ };
+
+ for (const auto ¬ification : params->getNotifications()) {
+ if (typeid(*notification) == typeid(notifications::NotSeenSMSNotification)) {
+ auto sms = static_cast<const notifications::NotSeenSMSNotification *>(notification.get());
+ internalData.push_back(create(sms));
+ }
+ else if (typeid(*notification) == typeid(notifications::NotSeenCallNotification)) {
+ auto call = static_cast<const notifications::NotSeenCallNotification *>(notification.get());
+ internalData.push_back(create(call));
+ }
+ }
+
+ list->rebuildList(listview::RebuildType::InPlace);
+ list->prepareRebuildCallback = nullptr;
+}
+
+void NotificationsModel::clearAll()
+{
+ list->reset();
+ eraseInternalData();
+}
+
+void NotificationsModel::setParentWindow(AppWindow *parentWindow) noexcept
+{
+ parent = parentWindow;
+}
A module-apps/notifications/NotificationsModel.hpp => module-apps/notifications/NotificationsModel.hpp +41 -0
@@ 0,0 1,41 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "NotificationListItem.hpp"
+#include "NotificationData.hpp"
+#include "ListItemProvider.hpp"
+
+#include "Application.hpp"
+#include "InternalModel.hpp"
+#include <service-appmgr/data/NotificationsChangedActionsParams.hpp>
+
+namespace gui
+{
+
+ class NotificationsModel : public app::InternalModel<gui::NotificationListItem *>, public gui::ListItemProvider
+ {
+ [[nodiscard]] unsigned int requestRecordsCount() final;
+ [[nodiscard]] unsigned int getMinimalItemHeight() const final;
+ ListItem *getItem(Order order) final;
+ void requestRecords(uint32_t offset, uint32_t limit) final;
+
+ protected:
+ AppWindow *parent = nullptr;
+ [[nodiscard]] virtual auto create(const notifications::NotSeenSMSNotification *notification)
+ -> NotificationListItem *;
+ [[nodiscard]] virtual auto create(const notifications::NotSeenCallNotification *notification)
+ -> NotificationListItem *;
+
+ public:
+ [[nodiscard]] bool isEmpty() const noexcept;
+ [[nodiscard]] bool hasDismissibleNotification() const noexcept;
+
+ void updateData(app::manager::actions::NotificationsChangedParams *params);
+ void dismissAll(const InputEvent &event);
+ void clearAll();
+ void setParentWindow(AppWindow *parentWindow) noexcept;
+ };
+
+} // namespace gui
M module-gui/gui/widgets/ListView.cpp => module-gui/gui/widgets/ListView.cpp +14 -0
@@ 161,6 161,16 @@ namespace gui
}
};
+ focusChangedCallback = [this]([[maybe_unused]] Item &item) -> bool {
+ if (focus) {
+ setFocus();
+ }
+ else {
+ setFocusItem(nullptr);
+ }
+ return true;
+ };
+
body->parentOnRequestedResizeCallback = [this]() {
if (pageLoaded)
recalculateOnBoxRequestedResize();
@@ 575,6 585,10 @@ namespace gui
void ListView::setFocus()
{
+ if (!focus) {
+ return;
+ }
+
setFocusItem(body);
if (storedFocusIndex != listview::nPos) {
M module-gui/gui/widgets/Style.hpp => module-gui/gui/widgets/Style.hpp +18 -0
@@ 244,4 244,22 @@ namespace style
inline constexpr auto rightMargin = 10U;
} // namespace widgets
+ namespace notifications
+ {
+ inline constexpr auto spanSize = 8;
+ inline constexpr auto digitSize = 16;
+ inline constexpr auto iconWidth = 35;
+ inline constexpr auto textMaxWidth = 250;
+ inline constexpr auto itemHeight = 55;
+
+ namespace model
+ {
+ inline constexpr auto maxNotificationsPerPage = 4;
+ inline constexpr auto x = 20;
+ inline constexpr auto y = 284;
+ inline constexpr auto w = style::window::default_body_width;
+ inline constexpr auto h = itemHeight * maxNotificationsPerPage;
+ } // namespace model
+ } // namespace notifications
+
}; // namespace style
M module-gui/test/mock/TestListViewProvider.hpp => module-gui/test/mock/TestListViewProvider.hpp +1 -1
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
M module-services/service-appmgr/CMakeLists.txt => module-services/service-appmgr/CMakeLists.txt +1 -0
@@ 7,6 7,7 @@ set(SOURCES
data/UsbActionsParams.cpp
data/SimActionsParams.cpp
data/MmiActionsParams.cpp
+ data/NotificationsChangedActionsParams.cpp
model/ApplicationManager.cpp
model/ApplicationHandle.cpp
model/ApplicationsRegistry.cpp
M module-services/service-appmgr/Controller.cpp => module-services/service-appmgr/Controller.cpp +8 -1
@@ 4,6 4,7 @@
#include "service-appmgr/Controller.hpp"
#include "service-appmgr/model/ApplicationManager.hpp"
+#include "service-appmgr/messages/GetAllNotificationsRequest.hpp"
#include <Service/Service.hpp>
@@ 36,7 37,7 @@ namespace app::manager
{
setOnSwitchBehaviour(data, onSwitchBehaviour);
auto msg = std::make_shared<app::manager::ActionRequest>(sender->GetName(), actionId, std::move(data));
- return sender->bus.sendUnicast(msg, ApplicationManager::ServiceName);
+ return sender->bus.sendUnicast(std::move(msg), ApplicationManager::ServiceName);
}
auto Controller::switchBack(sys::Service *sender, std::unique_ptr<SwitchBackRequest> msg) -> bool
@@ 111,4 112,10 @@ namespace app::manager
auto msg = std::make_shared<app::manager::PowerSaveModeInitRequest>(sender->GetName());
return sender->bus.sendUnicast(msg, ApplicationManager::ServiceName);
}
+
+ auto Controller::requestNotifications(sys::Service *sender) -> bool
+ {
+ auto msg = std::make_shared<app::manager::GetAllNotificationsRequest>();
+ return sender->bus.sendUnicast(std::move(msg), ApplicationManager::ServiceName);
+ }
} // namespace app::manager
A module-services/service-appmgr/data/NotificationsChangedActionsParams.cpp => module-services/service-appmgr/data/NotificationsChangedActionsParams.cpp +17 -0
@@ 0,0 1,17 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <service-appmgr/data/NotificationsChangedActionsParams.hpp>
+
+#include <module-apps/notifications/NotificationData.hpp>
+
+using namespace app::manager::actions;
+
+NotificationsChangedParams::NotificationsChangedParams(Notifications notifications)
+ : notifications{std::move(notifications)}
+{}
+
+auto NotificationsChangedParams::getNotifications() const noexcept -> const Notifications &
+{
+ return notifications;
+}
M module-services/service-appmgr/model/ApplicationManager.cpp => module-services/service-appmgr/model/ApplicationManager.cpp +33 -5
@@ 36,6 36,7 @@
#include <module-utils/time/DateAndTimeSettings.hpp>
#include <module-services/service-db/agents/settings/SystemSettings.hpp>
#include <service-appmgr/messages/DOMRequest.hpp>
+#include <service-appmgr/messages/GetAllNotificationsRequest.hpp>
#include "module-services/service-appmgr/service-appmgr/messages/ApplicationStatus.hpp"
@@ 131,14 132,15 @@ namespace app::manager
const ApplicationName &_rootApplicationName)
: Service{serviceName, {}, ApplicationManagerStackDepth},
ApplicationManagerBase(std::move(launchers)), rootApplicationName{_rootApplicationName},
- actionsRegistry{[this](ActionEntry &action) { return handleAction(action); }}, autoLockEnabled(false),
- settings(std::make_unique<settings::Settings>(this)),
+ actionsRegistry{[this](ActionEntry &action) { return handleAction(action); }}, notificationProvider(this),
+ autoLockEnabled(false), settings(std::make_unique<settings::Settings>(this)),
phoneModeObserver(std::make_unique<sys::phone_modes::Observer>())
{
autoLockTimer = sys::TimerFactory::createSingleShotTimer(
this, timerBlock, sys::timer::InfiniteTimeout, [this](sys::Timer &) { onPhoneLocked(); });
bus.channels.push_back(sys::BusChannel::PhoneModeChanges);
bus.channels.push_back(sys::BusChannel::ServiceAudioNotifications);
+ bus.channels.push_back(sys::BusChannel::ServiceDBNotifications);
registerMessageHandlers();
}
@@ 382,6 384,21 @@ namespace app::manager
handleSetOsUpdateVersionChange(msg);
return sys::msgHandled();
});
+ connect(typeid(GetAllNotificationsRequest), [&](sys::Message *request) {
+ notificationProvider.requestNotSeenNotifications();
+ notificationProvider.send();
+ return sys::msgHandled();
+ });
+ connect(typeid(db::NotificationMessage), [&](sys::Message *msg) {
+ auto msgl = static_cast<db::NotificationMessage *>(msg);
+ notificationProvider.handle(msgl);
+ return sys::msgHandled();
+ });
+ connect(typeid(db::QueryResponse), [&](sys::Message *msg) {
+ auto response = static_cast<db::QueryResponse *>(msg);
+ handleDBResponse(response);
+ return sys::msgHandled();
+ });
connect(typeid(app::manager::DOMRequest), [&](sys::Message *request) { return handleDOMRequest(request); });
@@ 578,7 595,9 @@ namespace app::manager
case actions::ShowPopup:
[[fallthrough]];
case actions::AbortPopup:
- return handlePopupAction(action);
+ return handleActionOnFocusedApp(action);
+ case actions::NotificationsChanged:
+ return handleActionOnFocusedApp(action);
default:
return handleCustomAction(action);
}
@@ 621,14 640,13 @@ namespace app::manager
return ActionProcessStatus::Skipped;
}
- auto ApplicationManager::handlePopupAction(ActionEntry &action) -> ActionProcessStatus
+ auto ApplicationManager::handleActionOnFocusedApp(ActionEntry &action) -> ActionProcessStatus
{
auto targetApp = getFocusedApplication();
if (targetApp == nullptr) {
return ActionProcessStatus::Skipped;
}
action.setTargetApplication(targetApp->name());
-
auto ¶ms = action.params;
app::Application::requestAction(this, targetApp->name(), action.actionId, std::move(params));
return ActionProcessStatus::Accepted;
@@ 846,6 864,16 @@ namespace app::manager
return true;
}
+ auto ApplicationManager::handleDBResponse(db::QueryResponse *msg) -> bool
+ {
+ auto result = msg->getResult();
+ if (auto response = dynamic_cast<db::query::notifications::GetAllResult *>(result.get())) {
+ notificationProvider.handle(response);
+ return true;
+ }
+ return false;
+ }
+
void ApplicationManager::rebuildActiveApplications()
{
for (const auto &app : getApplications()) {
M module-services/service-appmgr/service-appmgr/Actions.hpp => module-services/service-appmgr/service-appmgr/Actions.hpp +1 -0
@@ 61,6 61,7 @@ namespace app::manager
SMSRejectedByOfflineNotification,
CallRejectedByOfflineNotification,
PhoneModeChanged,
+ NotificationsChanged,
ShowPopup,
AbortPopup,
UserAction // The last enumerator in the Action enum.
M module-services/service-appmgr/service-appmgr/Controller.hpp => module-services/service-appmgr/service-appmgr/Controller.hpp +1 -0
@@ 53,5 53,6 @@ namespace app::manager
static auto changeDateFormat(sys::Service *sender, utils::time::Locale::DateFormat dateFormat) -> bool;
static auto changePowerSaveMode(sys::Service *sender) -> bool;
static auto preventBlockingDevice(sys::Service *sender) -> bool;
+ static auto requestNotifications(sys::Service *sender) -> bool;
};
} // namespace app::manager
A module-services/service-appmgr/service-appmgr/data/NotificationsChangedActionsParams.hpp => module-services/service-appmgr/service-appmgr/data/NotificationsChangedActionsParams.hpp +27 -0
@@ 0,0 1,27 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <service-appmgr/Actions.hpp>
+#include <list>
+
+namespace notifications
+{
+ class Notification;
+}
+
+namespace app::manager::actions
+{
+ class NotificationsChangedParams : public app::manager::actions::ActionParams
+ {
+ public:
+ using Notifications = std::list<std::shared_ptr<const notifications::Notification>>;
+ explicit NotificationsChangedParams(Notifications notifications);
+
+ [[nodiscard]] auto getNotifications() const noexcept -> const Notifications &;
+
+ private:
+ Notifications notifications;
+ };
+} // namespace app::manager::actions
A module-services/service-appmgr/service-appmgr/messages/GetAllNotificationsRequest.hpp => module-services/service-appmgr/service-appmgr/messages/GetAllNotificationsRequest.hpp +10 -0
@@ 0,0 1,10 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+namespace app::manager
+{
+ class GetAllNotificationsRequest : public sys::DataMessage
+ {};
+} // namespace app::manager
M module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp => module-services/service-appmgr/service-appmgr/model/ApplicationManager.hpp +5 -1
@@ 30,6 30,8 @@
#include <service-gui/Common.hpp>
#include <service-eink/Common.hpp>
+#include <notifications/NotificationProvider.hpp>
+
namespace app
{
class ApplicationLauncher;
@@ 123,7 125,7 @@ namespace app::manager
void handleActionRequest(ActionRequest *actionMsg);
auto handleHomeAction(ActionEntry &action) -> ActionProcessStatus;
auto handleLaunchAction(ActionEntry &action) -> ActionProcessStatus;
- auto handlePopupAction(ActionEntry &action) -> ActionProcessStatus;
+ auto handleActionOnFocusedApp(ActionEntry &action) -> ActionProcessStatus;
auto handlePhoneModeChangedAction(ActionEntry &action) -> ActionProcessStatus;
void handlePhoneModeChanged(sys::phone_modes::PhoneMode phoneMode);
void changePhoneMode(sys::phone_modes::PhoneMode phoneMode, const ApplicationHandle *app);
@@ 140,6 142,7 @@ namespace app::manager
auto handleTimeFormatChange(TimeFormatChangeRequest *msg) -> bool;
auto handleDateFormatChange(DateFormatChangeRequest *msg) -> bool;
auto handleSetOsUpdateVersionChange(SetOsUpdateVersion *msg) -> bool;
+ auto handleDBResponse(db::QueryResponse *msg) -> bool;
auto handlePowerSavingModeInit() -> bool;
auto handleMessageAsAction(sys::Message *request) -> std::shared_ptr<sys::ResponseMessage>;
/// handles dom request by passing this request to application which should provide the dom
@@ 165,6 168,7 @@ namespace app::manager
ApplicationName rootApplicationName;
ActionsRegistry actionsRegistry;
+ notifications::NotificationProvider notificationProvider;
bool autoLockEnabled; ///< a flag which indicates whether the autoLockTimer should be armed.
/// @note: The flag value depends on database settings "gs_lock_time". If the