From 46c57aaa889c92a47a4ac2d82aace687a9dae3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kamo=C5=84?= Date: Wed, 28 Apr 2021 15:43:11 +0200 Subject: [PATCH] [EGD-6599] Add single number call notification This PR adds proper notification on call notifications coming from single number. To that end following changes have been introduced: * extension of Notification DB record with contact_id filed * use of `ContactRecordInterface` in `NotificationsRecordInterface` * extension of `Increment` query to require `PhoneNumber::View` * multiple minor changes on path from creating/handling `NotificationsRecord` to displaying respective notification. --- enabled_unittests | 2 + image/user/db/notifications_001.sql | 3 +- image/user/db/notifications_002.sql | 7 +- .../models/ActiveNotificationsModel.cpp | 4 +- .../windows/DesktopMainWindow.cpp | 2 +- .../windows/DesktopMainWindow.hpp | 2 + .../notifications/NotificationData.cpp | 36 ++-- .../notifications/NotificationData.hpp | 24 +-- .../notifications/NotificationListItem.cpp | 7 +- .../notifications/NotificationProvider.cpp | 15 +- .../notifications/NotificationProvider.hpp | 4 +- .../notifications/NotificationsModel.cpp | 2 +- module-db/Databases/NotificationsDB.hpp | 4 +- module-db/Interface/NotificationsRecord.cpp | 83 ++++++---- module-db/Interface/NotificationsRecord.hpp | 22 +-- module-db/Tables/NotificationsTable.cpp | 27 +-- module-db/Tables/NotificationsTable.hpp | 8 +- .../calllog/QueryCalllogSetAllRead.hpp | 5 +- .../notifications/QueryNotificationsClear.cpp | 7 +- .../notifications/QueryNotificationsClear.hpp | 12 +- .../notifications/QueryNotificationsGet.cpp | 9 +- .../notifications/QueryNotificationsGet.hpp | 12 +- .../QueryNotificationsGetAll.hpp | 6 +- .../QueryNotificationsIncrement.cpp | 16 +- .../QueryNotificationsIncrement.hpp | 18 +- module-db/tests/CMakeLists.txt | 4 +- module-db/tests/NotificationsRecord_tests.cpp | 155 +++++++++++++++--- module-db/tests/NotificationsTable_tests.cpp | 26 +-- module-gui/gui/widgets/Style.hpp | 3 +- .../service-cellular/ServiceCellular.cpp | 34 ++-- .../service-cellular/ServiceCellular.hpp | 2 +- module-services/service-db/ServiceDB.cpp | 3 +- module-services/service-db/ServiceDB.hpp | 1 - 33 files changed, 378 insertions(+), 187 deletions(-) diff --git a/enabled_unittests b/enabled_unittests index 654eb109329049e8f79b29b9470911f583ed41ba..b04e527a1bbadb44aaac2ce9f59bca7aacfd7690 100644 --- a/enabled_unittests +++ b/enabled_unittests @@ -130,6 +130,8 @@ TESTS_LIST["catch2-db"]=" SMS Templates Table tests; Thread Record tests; Threads Table tests; + Notifications Table tests; + Notifications Record tests; " #--------- TESTS_LIST["catch2-db-initializer"]=" diff --git a/image/user/db/notifications_001.sql b/image/user/db/notifications_001.sql index 34d13fa792118432ef3bfa86a0e021bcba93c416..4d0278e5fb3ec8cf6e28275f7b9dbf9290c26b0d 100644 --- a/image/user/db/notifications_001.sql +++ b/image/user/db/notifications_001.sql @@ -4,5 +4,6 @@ CREATE TABLE IF NOT EXISTS notifications( _id INTEGER PRIMARY KEY, key INTEGER UNIQUE DEFAULT 0, - value INTEGER DEFAULT 0 + value INTEGER DEFAULT 0, + contact_id INTEGER DEFAULT 0 ); diff --git a/image/user/db/notifications_002.sql b/image/user/db/notifications_002.sql index 3b97c13dff66237808b4591007203e86753cdfc9..d7d4169091296f16606ca86caa94d830b5ae46db 100644 --- a/image/user/db/notifications_002.sql +++ b/image/user/db/notifications_002.sql @@ -1,7 +1,6 @@ -- Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. -- For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md -INSERT OR IGNORE INTO notifications (key, value) VALUES - ('1', '0'), - ('2', '0'); - +INSERT OR IGNORE INTO notifications (key, value, contact_id) VALUES + ('1', '0', '0'), + ('2', '0', '0'); diff --git a/module-apps/application-desktop/models/ActiveNotificationsModel.cpp b/module-apps/application-desktop/models/ActiveNotificationsModel.cpp index f2b613d423206552e6ecc8e17957bf5cd5ddcdb5..267cae35cd4c50b5b14ed40f064d25c6dffa38a2 100644 --- a/module-apps/application-desktop/models/ActiveNotificationsModel.cpp +++ b/module-apps/application-desktop/models/ActiveNotificationsModel.cpp @@ -63,8 +63,8 @@ auto ActiveNotificationsModel::create(const notifications::NotSeenCallNotificati std::function onKeyLeftFunctionalCallback = nullptr; if (notification->hasRecord()) { - if (const auto &record = notification->getRecord(); !record->numbers.empty()) { - onKeyLeftFunctionalCallback = [this, number = record->numbers[0].number]() { + 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(number)); diff --git a/module-apps/application-desktop/windows/DesktopMainWindow.cpp b/module-apps/application-desktop/windows/DesktopMainWindow.cpp index 38a31ef0e7056d381bc0b5909cbc47b51c0dfe0b..cba10cd3667f23b7f8cc29646ec6b4c836beb8c7 100644 --- a/module-apps/application-desktop/windows/DesktopMainWindow.cpp +++ b/module-apps/application-desktop/windows/DesktopMainWindow.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -136,7 +137,6 @@ namespace gui return app::manager::Controller::sendAction( application, app::manager::actions::Dial, std::make_unique("+")); } - if (inputEvent.is(KeyCode::KEY_RF)) { application->switchWindow(popup::window::power_off_window); return true; diff --git a/module-apps/application-desktop/windows/DesktopMainWindow.hpp b/module-apps/application-desktop/windows/DesktopMainWindow.hpp index 618c20b20cc852c3f3a24312a85e328d2c923e32..bf8a4abc7302ca8ad22f252a79565a91a5595569 100644 --- a/module-apps/application-desktop/windows/DesktopMainWindow.hpp +++ b/module-apps/application-desktop/windows/DesktopMainWindow.hpp @@ -17,6 +17,8 @@ namespace app namespace gui { + class NotificationsModel; + class DesktopMainWindow : public AppWindow { protected: diff --git a/module-apps/notifications/NotificationData.cpp b/module-apps/notifications/NotificationData.cpp index 5e059b494e1fbcbff040e2086c9c03c9da1d3ae0..8522243e51eef87a7dac5c7c8afd3e390d605677 100644 --- a/module-apps/notifications/NotificationData.cpp +++ b/module-apps/notifications/NotificationData.cpp @@ -2,7 +2,7 @@ // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "NotificationData.hpp" - +#include uint32_t notifications::Notification::priorityPool = 0; using namespace notifications; @@ -35,33 +35,35 @@ auto Notification::getPriority() const noexcept -> uint32_t return priority; } -NotSeenSMSNotification::NotSeenSMSNotification(unsigned value) - : Notification(NotificationType::NotSeenSms), value{value} +NotificationWithContact::NotificationWithContact(NotificationType type, + unsigned value, + std::optional record) + : Notification(type), value{value}, record{std::move(record)} {} -auto NotSeenSMSNotification::getValue() const noexcept -> unsigned +auto NotificationWithContact::hasRecord() const noexcept -> bool { - return value; + return record.has_value(); } -NotSeenCallNotification::NotSeenCallNotification(unsigned value, std::unique_ptr record) - : Notification(NotificationType::NotSeenCall), value{value}, record{std::move(record)} -{} - -bool NotSeenCallNotification::hasRecord() const noexcept +auto NotificationWithContact::getRecord() const noexcept -> const ContactRecord & { - return record != nullptr; + Expects(hasRecord()); + return record.value(); } -auto NotSeenCallNotification::getRecord() const noexcept -> const std::unique_ptr & -{ - return record; -} - -auto NotSeenCallNotification::getValue() const noexcept -> unsigned +auto NotificationWithContact::getValue() const noexcept -> unsigned { return value; } +NotSeenSMSNotification::NotSeenSMSNotification(unsigned value, std::optional record) + : NotificationWithContact(NotificationType::NotSeenSms, value, std::move(record)) +{} + +NotSeenCallNotification::NotSeenCallNotification(unsigned value, std::optional record) + : NotificationWithContact(NotificationType::NotSeenCall, value, std::move(record)) +{} + TetheringNotification::TetheringNotification() : Notification(NotificationType::Tethering) {} diff --git a/module-apps/notifications/NotificationData.hpp b/module-apps/notifications/NotificationData.hpp index 9c40e849d0449a6df9377f17bf2800001e1d5359..598c2320567a4edf9a4fd55cc4dfe03e55e26808 100644 --- a/module-apps/notifications/NotificationData.hpp +++ b/module-apps/notifications/NotificationData.hpp @@ -44,26 +44,30 @@ namespace notifications virtual ~Notification() = default; }; - class NotSeenSMSNotification : public Notification + class NotificationWithContact : public Notification { unsigned value = 0; + std::optional record; + + protected: + NotificationWithContact(NotificationType type, unsigned value, std::optional record); public: - explicit NotSeenSMSNotification(unsigned value); + [[nodiscard]] auto hasRecord() const noexcept -> bool; + [[nodiscard]] auto getRecord() const noexcept -> const ContactRecord &; [[nodiscard]] auto getValue() const noexcept -> unsigned; }; - class NotSeenCallNotification : public Notification + class NotSeenSMSNotification : public NotificationWithContact { - unsigned value = 0; - std::unique_ptr record; - public: - explicit NotSeenCallNotification(unsigned value, std::unique_ptr record = nullptr); + NotSeenSMSNotification(unsigned value, std::optional record); + }; - [[nodiscard]] bool hasRecord() const noexcept; - [[nodiscard]] auto getRecord() const noexcept -> const std::unique_ptr &; - [[nodiscard]] auto getValue() const noexcept -> unsigned; + class NotSeenCallNotification : public NotificationWithContact + { + public: + NotSeenCallNotification(unsigned value, std::optional record); }; class TetheringNotification : public Notification diff --git a/module-apps/notifications/NotificationListItem.cpp b/module-apps/notifications/NotificationListItem.cpp index 431869f08b355622f5a2b0ee37b8883114f5321d..c9805d16c0cbdddd02f708c4430cd89b6557ce0b 100644 --- a/module-apps/notifications/NotificationListItem.cpp +++ b/module-apps/notifications/NotificationListItem.cpp @@ -12,7 +12,6 @@ #include using namespace gui; -// using namespace style::desktop; namespace { @@ -36,14 +35,15 @@ namespace 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); + new gui::TextFixedSize(nullptr, 0, 0, style::notifications::textMinWidth, style::notifications::itemHeight); + text->setMaximumSize(style::notifications::textMaxWidth, 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; + text->setTextLimitType(TextLimitType::MaxLines, 1); return text; } @@ -135,6 +135,7 @@ NotificationWithEventCounter::NotificationWithEventCounter(notifications::Notifi { box->addWidget(buildImageInactive("dot_12px_hard_alpha_W_G")); box->addWidget(buildNotificationCountText(indicator)); + text->setMaximumSize(text->getSize(Axis::X), Axis::X); } NotificationWithOnOffButton::NotificationWithOnOffButton(notifications::NotificationType type, gui::ButtonState state) diff --git a/module-apps/notifications/NotificationProvider.cpp b/module-apps/notifications/NotificationProvider.cpp index e0974934f5b763e88f71685fb3002a216c952a41..69662cbd7aaefff6248fa0df52b2af9be8ae2191 100644 --- a/module-apps/notifications/NotificationProvider.cpp +++ b/module-apps/notifications/NotificationProvider.cpp @@ -7,26 +7,29 @@ #include #include #include +#include using namespace notifications; NotificationProvider::NotificationProvider(sys::Service *ownerService) : ownerService{ownerService} {} -template bool NotificationProvider::handleNotSeenWithCounter(unsigned int value) +template +bool NotificationProvider::handleNotSeenWithCounter(NotificationsRecord &&record) { + auto value = record.value; if (notifications.count(type) > 0) { if (value == 0) { notifications.erase(type); return true; } if (auto notification = static_cast(notifications[type].get()); value > notification->getValue()) { - notifications[type] = std::make_shared(value); + notifications[type] = std::make_shared(value, std::move(record.contactRecord)); return true; } } else if (value > 0) { - notifications[type] = std::make_shared(value); + notifications[type] = std::make_shared(value, std::move(record.contactRecord)); return true; } return false; @@ -38,15 +41,15 @@ void NotificationProvider::handle(db::query::notifications::GetAllResult *msg) auto records = *msg->getResult(); bool notificationsChanged = false; - for (auto record : records) { + for (auto &&record : records) { switch (record.key) { case NotificationsRecord::Key::Calls: notificationsChanged |= - handleNotSeenWithCounter(record.value); + handleNotSeenWithCounter(std::move(record)); break; case NotificationsRecord::Key::Sms: notificationsChanged |= - handleNotSeenWithCounter(record.value); + handleNotSeenWithCounter(std::move(record)); break; default: break; diff --git a/module-apps/notifications/NotificationProvider.hpp b/module-apps/notifications/NotificationProvider.hpp index 7efbbc943b6458c69e8435c7d283b05a864de14f..0acfa0c3dc09cfc9f6fa352269f2ccb49a38a4de 100644 --- a/module-apps/notifications/NotificationProvider.hpp +++ b/module-apps/notifications/NotificationProvider.hpp @@ -11,6 +11,8 @@ namespace sys class Service; } +class NotificationsRecord; + namespace db { class NotificationMessage; @@ -25,7 +27,7 @@ namespace notifications class NotificationProvider { - template bool handleNotSeenWithCounter(unsigned int value); + template bool handleNotSeenWithCounter(NotificationsRecord &&record); public: explicit NotificationProvider(sys::Service *ownerService); diff --git a/module-apps/notifications/NotificationsModel.cpp b/module-apps/notifications/NotificationsModel.cpp index d43b17f820f22f3699b0317ad251a69f9673fdaf..ba468928c5d55f76de557ec1104bc653c8a35fdf 100644 --- a/module-apps/notifications/NotificationsModel.cpp +++ b/module-apps/notifications/NotificationsModel.cpp @@ -65,7 +65,7 @@ auto NotificationsModel::create(const notifications::NotSeenCallNotification *no utils::to_string(notification->getValue())); if (notification->hasRecord()) { const auto &record = notification->getRecord(); - item->setName(record->getFormattedName()); + item->setName(record.getFormattedName()); } else { item->setName(utils::translate("app_desktop_missed_calls"), true); diff --git a/module-db/Databases/NotificationsDB.hpp b/module-db/Databases/NotificationsDB.hpp index 8270375f038c285d0dbe3ceeb5a53dd851244b7f..edfc817e1635016fc4614769d6dafc9ef0485030 100644 --- a/module-db/Databases/NotificationsDB.hpp +++ b/module-db/Databases/NotificationsDB.hpp @@ -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 @@ -9,7 +9,7 @@ class NotificationsDB : public Database { public: - NotificationsDB(const char *name); + explicit NotificationsDB(const char *name); virtual ~NotificationsDB() = default; NotificationsTable notifications; diff --git a/module-db/Interface/NotificationsRecord.cpp b/module-db/Interface/NotificationsRecord.cpp index 6d55bd7276721c91f1a127e1e43e425e9b0a0881..d6b3c7910cf9edb343b978c2b2e852af0e16a477 100644 --- a/module-db/Interface/NotificationsRecord.cpp +++ b/module-db/Interface/NotificationsRecord.cpp @@ -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 #include "NotificationsRecord.hpp" @@ -6,15 +6,17 @@ #include "module-db/queries/notifications/QueryNotificationsIncrement.hpp" #include "module-db/queries/notifications/QueryNotificationsClear.hpp" #include "module-db/queries/notifications/QueryNotificationsGetAll.hpp" +#include "Databases/NotificationsDB.hpp" #include #include #include #include +#include -NotificationsRecord::NotificationsRecord(const NotificationsTableRow &tableRow) - : Record{tableRow.ID}, value{tableRow.value} +NotificationsRecord::NotificationsRecord(const NotificationsTableRow &tableRow, std::optional record) + : Record{tableRow.ID}, value{tableRow.value}, contactRecord{std::move(record)} { if (tableRow.key > static_cast(Key::NotValidKey) && tableRow.key < static_cast(Key::NumberOfKeys)) { @@ -26,16 +28,6 @@ NotificationsRecord::NotificationsRecord(const NotificationsTableRow &tableRow) ID = DB_ID_NONE; } -bool NotificationsRecord::isValidRecord() const -{ - return isValid() && gotValidKey(); -} - -bool NotificationsRecord::gotValidKey() const -{ - return isValidKey(key); -} - bool NotificationsRecord::isValidKey(Key key) { return key != Key::NotValidKey && key != Key::NumberOfKeys; @@ -44,13 +36,18 @@ bool NotificationsRecord::isValidKey(Key key) std::ostream &operator<<(std::ostream &out, const NotificationsRecord &rec) { out << " " << rec.ID << " " << static_cast(rec.key) << " " << rec.value; - + if (rec.contactRecord.has_value()) { + out << " " << rec.contactRecord.value().ID; + } return out; } -NotificationsRecordInterface::NotificationsRecordInterface(NotificationsDB *notificationsDb) - : notificationsDb(notificationsDb) -{} +NotificationsRecordInterface::NotificationsRecordInterface(NotificationsDB *notificationsDb, + ContactRecordInterface *contactsDb) + : notificationsDb(notificationsDb), contactsDb(contactsDb) +{ + Expects(contactsDb != nullptr); +} bool NotificationsRecordInterface::Add(const NotificationsRecord &rec) { @@ -79,7 +76,7 @@ std::unique_ptr> NotificationsRecordInterface:: auto records = std::make_unique>(); for (auto &r : rows) { - records->push_back(NotificationsRecord{r}); + records->push_back(NotificationsRecord{r, getContactRecord(r.contactID)}); } return records; @@ -92,8 +89,10 @@ bool NotificationsRecordInterface::Update(const NotificationsRecord &rec) return false; } - return notificationsDb->notifications.update( - NotificationsTableRow{{.ID = rec.ID}, .key = static_cast(rec.key), .value = rec.value}); + uint32_t contactId = rec.contactRecord.has_value() ? rec.contactRecord.value().ID : DB_ID_NONE; + + return notificationsDb->notifications.update(NotificationsTableRow{ + {.ID = rec.ID}, .key = static_cast(rec.key), .value = rec.value, .contactID = contactId}); } bool NotificationsRecordInterface::RemoveByID(uint32_t id) @@ -109,10 +108,20 @@ bool NotificationsRecordInterface::RemoveByField(NotificationsRecordField field, return false; } +std::optional NotificationsRecordInterface::getContactRecord(uint32_t id) const +{ + if (id != DB_ID_NONE) { + if (auto contactRecord = contactsDb->GetByIdWithTemporary(id); contactRecord.isValid()) { + return std::make_optional(std::move(contactRecord)); + } + } + return std::nullopt; +} NotificationsRecord NotificationsRecordInterface::GetByID(uint32_t id) { - return NotificationsRecord{notificationsDb->notifications.getById(id)}; + auto tableRow = notificationsDb->notifications.getById(id); + return NotificationsRecord{tableRow, getContactRecord(tableRow.contactID)}; } uint32_t NotificationsRecordInterface::GetCount() @@ -126,8 +135,8 @@ NotificationsRecord NotificationsRecordInterface::GetByKey(NotificationsRecord:: return NotificationsRecord(); } - NotificationsTableRow notificationsTableRow = notificationsDb->notifications.GetByKey(static_cast(key)); - return NotificationsRecord{notificationsTableRow}; + auto tableRow = notificationsDb->notifications.getByKey(static_cast(key)); + return NotificationsRecord{tableRow, getContactRecord(tableRow.contactID)}; } std::unique_ptr NotificationsRecordInterface::runQuery(std::shared_ptr query) @@ -150,17 +159,28 @@ std::unique_ptr NotificationsRecordInterface::runQuery(std::sha std::unique_ptr NotificationsRecordInterface::runQueryImpl( const db::query::notifications::Get *query) { - auto value = GetByKey(query->key); - return std::make_unique(value); + auto value = GetByKey(query->getKey()); + return std::make_unique(std::move(value)); } std::unique_ptr NotificationsRecordInterface::runQueryImpl( const db::query::notifications::Increment *query) { auto ret = false; - - auto record = GetByKey(query->key); - if (record.isValid() && record.key == query->key) { + if (auto record = GetByKey(query->getKey()); record.isValid()) { + auto ¤tContactRecord = record.contactRecord; + if (auto numberMatch = contactsDb->MatchByNumber(query->getNumber()); numberMatch.has_value()) { + if (record.value == 0) { + currentContactRecord = std::move(numberMatch.value().contact); + } + else if (currentContactRecord.has_value() && + numberMatch.value().contactId != currentContactRecord.value().ID) { + currentContactRecord.reset(); + } + } + else { + currentContactRecord.reset(); + } record.value++; ret = Update(record); } @@ -171,11 +191,10 @@ std::unique_ptr NotificationsRecordInterf const db::query::notifications::Clear *query) { auto ret = false; - - auto record = GetByKey(query->key); - if (record.isValid() && record.key == query->key) { + if (auto record = GetByKey(query->getKey()); record.isValid()) { record.value = 0; - ret = Update(record); + record.contactRecord.reset(); + ret = Update(record); } return std::make_unique(ret); } diff --git a/module-db/Interface/NotificationsRecord.hpp b/module-db/Interface/NotificationsRecord.hpp index 0deb8bd3e4b9418f351ef0174c83d05406445328..73d1a66702fbe05b79e8ea5487060bde7be6d3f2 100644 --- a/module-db/Interface/NotificationsRecord.hpp +++ b/module-db/Interface/NotificationsRecord.hpp @@ -1,18 +1,21 @@ -// 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 #include "Common/Common.hpp" -#include "Databases/NotificationsDB.hpp" +#include "module-db/Tables/NotificationsTable.hpp" #include "Record.hpp" +#include "Interface/ContactRecord.hpp" #include - #include #include // fw declarations +class ContactRecordInterface; +class NotificationsDB; + namespace db::query::notifications { class Get; @@ -37,15 +40,13 @@ struct NotificationsRecord : public Record Key key = Key::NotValidKey; uint32_t value = 0; + std::optional contactRecord; friend std::ostream &operator<<(std::ostream &out, const NotificationsRecord &point); NotificationsRecord() = default; - ~NotificationsRecord() = default; - explicit NotificationsRecord(const NotificationsTableRow &tableRow); - - bool isValidRecord() const; - bool gotValidKey() const; + explicit NotificationsRecord(const NotificationsTableRow &tableRow, + std::optional record = std::nullopt); static bool isValidKey(Key key); }; @@ -58,8 +59,7 @@ enum class NotificationsRecordField class NotificationsRecordInterface : public RecordInterface { public: - explicit NotificationsRecordInterface(NotificationsDB *notificationsDb); - virtual ~NotificationsRecordInterface() = default; + NotificationsRecordInterface(NotificationsDB *notificationsDb, ContactRecordInterface *contactsDb); bool Add(const NotificationsRecord &rec) override final; bool RemoveByID(uint32_t id) override final; @@ -79,7 +79,9 @@ class NotificationsRecordInterface : public RecordInterface getContactRecord(uint32_t id) const; std::unique_ptr runQueryImpl(const db::query::notifications::Get *query); std::unique_ptr runQueryImpl( const db::query::notifications::Increment *query); diff --git a/module-db/Tables/NotificationsTable.cpp b/module-db/Tables/NotificationsTable.cpp index 108ccbfb22d3474c2c07843fba7e2b416877298c..f22172171fc154d238cb248c4677ef2756771386 100644 --- a/module-db/Tables/NotificationsTable.cpp +++ b/module-db/Tables/NotificationsTable.cpp @@ -1,12 +1,11 @@ -// 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 #include "NotificationsTable.hpp" -#include "module-db/Interface/NotificationsRecord.hpp" +#include "Database/Database.hpp" #include #include - #include NotificationsTable::NotificationsTable(Database *db) : Table(db) @@ -19,7 +18,10 @@ bool NotificationsTable::create() bool NotificationsTable::add(NotificationsTableRow entry) { - return db->execute("INSERT or IGNORE INTO notifications (key, value) VALUES (%lu, %lu);", entry.key, entry.value); + return db->execute("INSERT or IGNORE INTO notifications (key, value, contact_id) VALUES (%lu, %lu, %lu);", + entry.key, + entry.value, + entry.contactID); } bool NotificationsTable::removeById(uint32_t id) @@ -42,8 +44,11 @@ bool NotificationsTable::removeByField(NotificationsTableFields field, const cha bool NotificationsTable::update(NotificationsTableRow entry) { - return db->execute( - "UPDATE notifications SET key = %lu, value = %lu WHERE _id = %lu;", entry.key, entry.value, entry.ID); + return db->execute("UPDATE notifications SET key = %lu, value = %lu, contact_id = %lu WHERE _id = %lu;", + entry.key, + entry.value, + entry.contactID, + entry.ID); } NotificationsTableRow NotificationsTable::getById(uint32_t id) @@ -59,12 +64,12 @@ NotificationsTableRow NotificationsTable::getById(uint32_t id) return NotificationsTableRow{ (*retQuery)[0].getUInt32(), // ID (*retQuery)[1].getUInt32(), // key - (*retQuery)[2].getUInt32() // value - + (*retQuery)[2].getUInt32(), // value + (*retQuery)[3].getUInt32() // contactID }; } -NotificationsTableRow NotificationsTable::GetByKey(uint32_t key) +NotificationsTableRow NotificationsTable::getByKey(uint32_t key) { auto retQuery = db->query("SELECT * FROM notifications WHERE key= %u;", key); @@ -77,7 +82,8 @@ NotificationsTableRow NotificationsTable::GetByKey(uint32_t key) return NotificationsTableRow{ (*retQuery)[0].getUInt32(), // ID (*retQuery)[1].getUInt32(), // key - (*retQuery)[2].getUInt32() // value + (*retQuery)[2].getUInt32(), // value + (*retQuery)[3].getUInt32() // contactID }; } @@ -96,6 +102,7 @@ std::vector NotificationsTable::getLimitOffset(uint32_t o (*retQuery)[0].getUInt32(), // ID (*retQuery)[1].getUInt32(), // key (*retQuery)[2].getUInt32(), // value + (*retQuery)[3].getUInt32() // contactID }); } while (retQuery->nextRow()); diff --git a/module-db/Tables/NotificationsTable.hpp b/module-db/Tables/NotificationsTable.hpp index a86140cb08e6accd1be4cd5afda2b05f4475b78d..ba408f9979f121d5397aef0596950c348e70ec72 100644 --- a/module-db/Tables/NotificationsTable.hpp +++ b/module-db/Tables/NotificationsTable.hpp @@ -1,18 +1,20 @@ -// 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 #include "Table.hpp" #include "Record.hpp" -#include "Database/Database.hpp" #include "utf8/UTF8.hpp" #include "Common/Common.hpp" +class Database; + struct NotificationsTableRow : public Record { uint32_t key = 0; uint32_t value = 0; + uint32_t contactID = DB_ID_NONE; }; enum class NotificationsTableFields @@ -32,7 +34,7 @@ class NotificationsTable : public Table getLimitOffset(uint32_t offset, uint32_t limit) override final; diff --git a/module-db/queries/calllog/QueryCalllogSetAllRead.hpp b/module-db/queries/calllog/QueryCalllogSetAllRead.hpp index 5c2332012dcb9442e10ab54c3d013c5ffd6b9225..99f6345f34d3db688074ff5cdd97ea971e5bd8e9 100644 --- a/module-db/queries/calllog/QueryCalllogSetAllRead.hpp +++ b/module-db/queries/calllog/QueryCalllogSetAllRead.hpp @@ -1,9 +1,8 @@ -// 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 -#include "Interface/NotificationsRecord.hpp" #include #include @@ -20,7 +19,7 @@ namespace db::query::calllog class SetAllReadResult : public QueryResult { public: - SetAllReadResult(bool ret); + explicit SetAllReadResult(bool ret); [[nodiscard]] auto debugInfo() const -> std::string override; const bool ret = true; diff --git a/module-db/queries/notifications/QueryNotificationsClear.cpp b/module-db/queries/notifications/QueryNotificationsClear.cpp index 156d0b9aed49d7e47a42c611ab15e65fafc98aa7..8c687b112321d0d8aa0d76fccd334d4c97e3af97 100644 --- a/module-db/queries/notifications/QueryNotificationsClear.cpp +++ b/module-db/queries/notifications/QueryNotificationsClear.cpp @@ -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 #include "QueryNotificationsClear.hpp" @@ -13,6 +13,11 @@ namespace db::query::notifications return "Clear"; } + auto Clear::getKey() const noexcept -> NotificationsRecord::Key + { + return key; + } + ClearResult::ClearResult(bool ret) : ret(ret) {} diff --git a/module-db/queries/notifications/QueryNotificationsClear.hpp b/module-db/queries/notifications/QueryNotificationsClear.hpp index 35992786980a290b72b7dddb85e57df1a42bffc6..20f1f23970bb641d2c76b95e633e4734a1f84a68 100644 --- a/module-db/queries/notifications/QueryNotificationsClear.hpp +++ b/module-db/queries/notifications/QueryNotificationsClear.hpp @@ -1,9 +1,9 @@ -// 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 -#include "module-db/Interface/NotificationsRecord.hpp" +#include #include #include @@ -11,10 +11,12 @@ namespace db::query::notifications { class Clear : public Query { - public: const NotificationsRecord::Key key; - Clear(NotificationsRecord::Key key); + public: + explicit Clear(NotificationsRecord::Key key); + + [[nodiscard]] auto getKey() const noexcept -> NotificationsRecord::Key; [[nodiscard]] auto debugInfo() const -> std::string override; }; @@ -23,7 +25,7 @@ namespace db::query::notifications bool ret; public: - ClearResult(bool ret); + explicit ClearResult(bool ret); [[nodiscard]] auto getResult() const -> bool; [[nodiscard]] auto debugInfo() const -> std::string override; diff --git a/module-db/queries/notifications/QueryNotificationsGet.cpp b/module-db/queries/notifications/QueryNotificationsGet.cpp index 2e4b7959b2cfa137490e6bd70d4bd4ec3636e465..a3d7c42f1f9348532978902d88d3dace42464cc0 100644 --- a/module-db/queries/notifications/QueryNotificationsGet.cpp +++ b/module-db/queries/notifications/QueryNotificationsGet.cpp @@ -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 #include "QueryNotificationsGet.hpp" @@ -13,7 +13,12 @@ namespace db::query::notifications return "Get"; } - GetResult::GetResult(NotificationsRecord record) : record(record) + auto Get::getKey() const noexcept -> NotificationsRecord::Key + { + return key; + } + + GetResult::GetResult(NotificationsRecord record) : record(std::move(record)) {} auto GetResult::getResult() const -> NotificationsRecord diff --git a/module-db/queries/notifications/QueryNotificationsGet.hpp b/module-db/queries/notifications/QueryNotificationsGet.hpp index c5ee5cbac4086719a7b3fd5fe24c48111941e917..3edacd125b306671f44a2a7ba5268daf1f505aae 100644 --- a/module-db/queries/notifications/QueryNotificationsGet.hpp +++ b/module-db/queries/notifications/QueryNotificationsGet.hpp @@ -1,9 +1,9 @@ -// 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 -#include "module-db/Interface/NotificationsRecord.hpp" +#include #include #include @@ -11,10 +11,12 @@ namespace db::query::notifications { class Get : public Query { - public: const NotificationsRecord::Key key; - Get(NotificationsRecord::Key key); + public: + explicit Get(NotificationsRecord::Key key); + + [[nodiscard]] auto getKey() const noexcept -> NotificationsRecord::Key; [[nodiscard]] auto debugInfo() const -> std::string override; }; @@ -23,7 +25,7 @@ namespace db::query::notifications NotificationsRecord record; public: - GetResult(NotificationsRecord record); + explicit GetResult(NotificationsRecord record); [[nodiscard]] auto getResult() const -> NotificationsRecord; [[nodiscard]] auto debugInfo() const -> std::string override; diff --git a/module-db/queries/notifications/QueryNotificationsGetAll.hpp b/module-db/queries/notifications/QueryNotificationsGetAll.hpp index 3ed912d1e82234a70ac88872605b5af165db821a..474e8a913c9a066aa097bf8cf9d0c19de584080c 100644 --- a/module-db/queries/notifications/QueryNotificationsGetAll.hpp +++ b/module-db/queries/notifications/QueryNotificationsGetAll.hpp @@ -1,9 +1,9 @@ -// 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 -#include "module-db/Interface/NotificationsRecord.hpp" +#include #include #include @@ -22,7 +22,7 @@ namespace db::query::notifications std::unique_ptr> records; public: - GetAllResult(std::unique_ptr> records); + explicit GetAllResult(std::unique_ptr> records); [[nodiscard]] auto getResult() -> std::unique_ptr>; [[nodiscard]] auto debugInfo() const -> std::string override; diff --git a/module-db/queries/notifications/QueryNotificationsIncrement.cpp b/module-db/queries/notifications/QueryNotificationsIncrement.cpp index 16dfd081edf69e83ed08716ec377a9c5e2fba2f5..4e2ab016f0c69ea07bfb20ced05e2b4e3fd60f8b 100644 --- a/module-db/queries/notifications/QueryNotificationsIncrement.cpp +++ b/module-db/queries/notifications/QueryNotificationsIncrement.cpp @@ -1,13 +1,23 @@ -// 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 #include "QueryNotificationsIncrement.hpp" namespace db::query::notifications { - Increment::Increment(NotificationsRecord::Key key) : Query(Query::Type::Update), key(key) + Increment::Increment(NotificationsRecord::Key key, const utils::PhoneNumber::View &number) + : Query(Query::Type::Update), key(key), number(number) {} + auto Increment::getKey() const noexcept -> NotificationsRecord::Key + { + return key; + } + auto Increment::getNumber() const noexcept -> const utils::PhoneNumber::View & + { + return number; + } + auto Increment::debugInfo() const -> std::string { return "Increment"; @@ -16,7 +26,7 @@ namespace db::query::notifications IncrementResult::IncrementResult(bool ret) : ret(ret) {} - auto IncrementResult::getResult() const -> bool + auto IncrementResult::getResult() const noexcept -> bool { return ret; } diff --git a/module-db/queries/notifications/QueryNotificationsIncrement.hpp b/module-db/queries/notifications/QueryNotificationsIncrement.hpp index 4815b4e2777a8b87019f4a826e1d826d005d3ca9..c26e1020aa6375b1310f77472c18091a8bb8a6ba 100644 --- a/module-db/queries/notifications/QueryNotificationsIncrement.hpp +++ b/module-db/queries/notifications/QueryNotificationsIncrement.hpp @@ -1,19 +1,25 @@ -// 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 -#include "module-db/Interface/NotificationsRecord.hpp" +#include #include #include +#include namespace db::query::notifications { class Increment : public Query { - public: const NotificationsRecord::Key key; - Increment(NotificationsRecord::Key key); + const utils::PhoneNumber::View number; + + public: + Increment(NotificationsRecord::Key key, const utils::PhoneNumber::View &number); + + [[nodiscard]] auto getKey() const noexcept -> NotificationsRecord::Key; + [[nodiscard]] auto getNumber() const noexcept -> const utils::PhoneNumber::View &; [[nodiscard]] auto debugInfo() const -> std::string override; }; @@ -23,8 +29,8 @@ namespace db::query::notifications bool ret; public: - IncrementResult(bool ret); - [[nodiscard]] auto getResult() const -> bool; + explicit IncrementResult(bool ret); + [[nodiscard]] auto getResult() const noexcept -> bool; [[nodiscard]] auto debugInfo() const -> std::string override; }; diff --git a/module-db/tests/CMakeLists.txt b/module-db/tests/CMakeLists.txt index 1a3ba5c3ea52a8beecb6f029bcb41b8710a1ef0a..3c35a6b7a6c643491dea415a968bf77e543e5830 100644 --- a/module-db/tests/CMakeLists.txt +++ b/module-db/tests/CMakeLists.txt @@ -22,8 +22,8 @@ add_catch2_executable( #EventsTable_tests.cpp NotesRecord_tests.cpp NotesTable_tests.cpp - #NotificationsRecord_tests.cpp - #NotificationsTable_tests.cpp + NotificationsRecord_tests.cpp + NotificationsTable_tests.cpp QueryInterface.cpp SMSRecord_tests.cpp SMSTable_tests.cpp diff --git a/module-db/tests/NotificationsRecord_tests.cpp b/module-db/tests/NotificationsRecord_tests.cpp index 8626b3fc327ce41f68bc9aa019202a87d176cd53..f0482d769e351d5460671c029007c93bb3f62653 100644 --- a/module-db/tests/NotificationsRecord_tests.cpp +++ b/module-db/tests/NotificationsRecord_tests.cpp @@ -1,15 +1,18 @@ // Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md +#include "common.hpp" #include -#include "Interface/NotificationsRecord.hpp" -#include "Database/Database.hpp" -#include "Databases/NotificationsDB.hpp" -#include "module-db/queries/notifications/QueryNotificationsGet.hpp" -#include "module-db/queries/notifications/QueryNotificationsIncrement.hpp" -#include "module-db/queries/notifications/QueryNotificationsClear.hpp" -#include "module-db/queries/notifications/QueryNotificationsGetAll.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include @@ -21,16 +24,6 @@ TEST_CASE("Notifications Record tests") { - Database::initialize(); - - const auto notificationsPath = (std::filesystem::path{"sys/user"} / "notifications.db"); - if (std::filesystem::exists(notificationsPath)) { - REQUIRE(std::filesystem::remove(notificationsPath)); - } - - NotificationsDB notificationsDb{notificationsPath.c_str()}; - - REQUIRE(notificationsDb.isInitialized()); SECTION("Default Constructor") { @@ -39,27 +32,43 @@ TEST_CASE("Notifications Record tests") REQUIRE(testRec.ID == DB_ID_NONE); REQUIRE(testRec.key == NotificationsRecord::Key::NotValidKey); REQUIRE(testRec.value == 0); + REQUIRE_FALSE(testRec.contactRecord.has_value()); } SECTION("Constructor from NotificationsTableRow") { NotificationsTableRow tableRow{ {.ID = 10}, .key = static_cast(NotificationsRecord::Key::Calls), .value = 2}; - NotificationsRecord testRec(tableRow); REQUIRE(testRec.isValid()); REQUIRE(testRec.ID == 10); REQUIRE(testRec.key == NotificationsRecord::Key::Calls); REQUIRE(testRec.value == 2); + REQUIRE_FALSE(testRec.contactRecord.has_value()); } + Database::initialize(); + const auto notificationsPath = (std::filesystem::path{"sys/user"} / "notifications.db"); + const auto contactsPath = (std::filesystem::path{"sys/user"} / "contacts.db"); + RemoveDbFiles(notificationsPath.stem()); + RemoveDbFiles(contactsPath.stem()); + + NotificationsDB notificationsDb{notificationsPath.c_str()}; + ContactsDB contactsDb{contactsPath.c_str()}; + REQUIRE(notificationsDb.isInitialized()); + REQUIRE(contactsDb.isInitialized()); + const auto notificationsCount = notificationsDb.notifications.count() + 1; // clear notifications table for (std::size_t id = 1; id <= notificationsCount; id++) { REQUIRE(notificationsDb.notifications.removeById(id)); } - NotificationsRecordInterface notificationsRecordInterface(¬ificationsDb); + + ContactRecordInterface contactRecordInterface(&contactsDb); + NotificationsRecordInterface notificationsRecordInterface(¬ificationsDb, &contactRecordInterface); + REQUIRE(contactRecordInterface.GetCount() == 0); REQUIRE(notificationsRecordInterface.GetCount() == 0); + NotificationsTableRow callsRow{ {.ID = DB_ID_NONE}, .key = static_cast(NotificationsRecord::Key::Calls), .value = 0}; @@ -80,12 +89,14 @@ TEST_CASE("Notifications Record tests") REQUIRE(callsNotifications.ID == 1); REQUIRE(callsNotifications.key == NotificationsRecord::Key::Calls); REQUIRE(callsNotifications.value == 0); + REQUIRE_FALSE(callsNotifications.contactRecord.has_value()); auto smsNotifications = notificationsRecordInterface.GetByID(2); REQUIRE(smsNotifications.isValid()); REQUIRE(smsNotifications.ID == 2); REQUIRE(smsNotifications.key == NotificationsRecord::Key::Sms); REQUIRE(smsNotifications.value == 0); + REQUIRE_FALSE(smsNotifications.contactRecord.has_value()); } SECTION("Get entry by key") @@ -180,7 +191,9 @@ TEST_CASE("Notifications Record tests") REQUIRE(entryPost.value == entryPre.value); } - auto getByKey = [&](NotificationsRecord::Key key, uint32_t val) { + auto getByKey = [&](NotificationsRecord::Key key, + uint32_t expectedValue, + const std::optional &expectedContactRecord = std::nullopt) { auto query = std::make_shared(key); auto ret = notificationsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); @@ -188,11 +201,16 @@ TEST_CASE("Notifications Record tests") auto record = result->getResult(); REQUIRE(record.isValid()); REQUIRE(record.key == key); - REQUIRE(record.value == val); + REQUIRE(record.value == expectedValue); + REQUIRE(record.contactRecord.has_value() == expectedContactRecord.has_value()); + if (expectedContactRecord.has_value()) { + REQUIRE(record.contactRecord.value().ID == expectedContactRecord.value().ID); + } }; - auto incrementByKey = [&](NotificationsRecord::Key key) { - auto query = std::make_shared(key); + auto incrementByKey = [&](NotificationsRecord::Key key, const std::string &phoneNumber = "+48500500500") { + utils::PhoneNumber number(phoneNumber); + auto query = std::make_shared(key, number.getView()); auto ret = notificationsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); @@ -253,5 +271,96 @@ TEST_CASE("Notifications Record tests") REQUIRE(records->size() == numberOfNotifcations); } + SECTION("Notification DB and Contact DB connection tests") + { + const std::string primaryNameTest_1 = "PrimaryTestNameOne"; + const std::string numberUserTest_1 = "600123456"; + ContactRecord testContactRecord_1; + testContactRecord_1.primaryName = primaryNameTest_1; + testContactRecord_1.numbers = + std::vector({ContactRecord::Number(utils::PhoneNumber(numberUserTest_1).getView())}); + + const std::string primaryNameTest_2 = "PrimaryTestNameTwo"; + const std::string numberUserTest_2 = "600600600"; + ContactRecord testContactRecord_2; + testContactRecord_2.primaryName = primaryNameTest_2; + testContactRecord_2.numbers = + std::vector({ContactRecord::Number(utils::PhoneNumber(numberUserTest_2).getView())}); + + REQUIRE(contactRecordInterface.Add(testContactRecord_1)); + REQUIRE(contactRecordInterface.Add(testContactRecord_2)); + + const auto someUnknownNumber = "500200300"; + const auto noNotificationExpected = 0; + const auto contactNotExpected = std::nullopt; + + SECTION("Tests preconditions") + { + getByKey(NotificationsRecord::Key::Calls, noNotificationExpected); + } + + SECTION("Single call notification from unknown number") + { + const auto expectedNotificationValue = 1; + incrementByKey(NotificationsRecord::Key::Calls, someUnknownNumber); + getByKey(NotificationsRecord::Key::Calls, expectedNotificationValue, contactNotExpected); + } + + SECTION("Single call notification from known number") + { + const auto expectedNotificationValue = 1; + incrementByKey(NotificationsRecord::Key::Calls, numberUserTest_1); + getByKey(NotificationsRecord::Key::Calls, expectedNotificationValue, testContactRecord_1); + clearByKey(NotificationsRecord::Key::Calls); + getByKey(NotificationsRecord::Key::Calls, noNotificationExpected, contactNotExpected); + } + + SECTION("Multiple call notifications from single known number") + { + const auto expectedNotificationValue = 3; + for (int i = 0; i < expectedNotificationValue; i++) + incrementByKey(NotificationsRecord::Key::Calls, numberUserTest_1); + getByKey(NotificationsRecord::Key::Calls, expectedNotificationValue, testContactRecord_1); + clearByKey(NotificationsRecord::Key::Calls); + getByKey(NotificationsRecord::Key::Calls, noNotificationExpected, contactNotExpected); + } + + SECTION("Multiple call notifications from multiple known numbers") + { + const auto expectedNotificationValue = 2 * 3; + for (int i = 0; i < expectedNotificationValue / 2; i++) { + incrementByKey(NotificationsRecord::Key::Calls, numberUserTest_1); + incrementByKey(NotificationsRecord::Key::Calls, numberUserTest_2); + } + getByKey(NotificationsRecord::Key::Calls, expectedNotificationValue, contactNotExpected); + clearByKey(NotificationsRecord::Key::Calls); + getByKey(NotificationsRecord::Key::Calls, noNotificationExpected, contactNotExpected); + } + + SECTION("Multiple call notifications in sequence of known-unknown-known numbers") + { + incrementByKey(NotificationsRecord::Key::Calls, numberUserTest_1); + getByKey(NotificationsRecord::Key::Calls, 1, testContactRecord_1); + + incrementByKey(NotificationsRecord::Key::Calls, someUnknownNumber); + getByKey(NotificationsRecord::Key::Calls, 2, contactNotExpected); + + incrementByKey(NotificationsRecord::Key::Calls, numberUserTest_1); + getByKey(NotificationsRecord::Key::Calls, 3, contactNotExpected); + } + + SECTION("Multiple call notifications in sequence of unknown-known-unknown numbers") + { + incrementByKey(NotificationsRecord::Key::Calls, someUnknownNumber); + getByKey(NotificationsRecord::Key::Calls, 1, contactNotExpected); + + incrementByKey(NotificationsRecord::Key::Calls, numberUserTest_1); + getByKey(NotificationsRecord::Key::Calls, 2, contactNotExpected); + + incrementByKey(NotificationsRecord::Key::Calls, someUnknownNumber); + getByKey(NotificationsRecord::Key::Calls, 3, contactNotExpected); + } + } + Database::deinitialize(); } diff --git a/module-db/tests/NotificationsTable_tests.cpp b/module-db/tests/NotificationsTable_tests.cpp index e071ce4ae08234e20d19e2383e4c9e736ce14495..b73753fc33e74882b18cf9233f6ce041658c0d5d 100644 --- a/module-db/tests/NotificationsTable_tests.cpp +++ b/module-db/tests/NotificationsTable_tests.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md +#include "common.hpp" #include #include "Database/Database.hpp" @@ -17,12 +18,8 @@ TEST_CASE("Notifications Table tests") { Database::initialize(); - const auto notificationsPath = (std::filesystem::path{"sys/user"} / "notifications.db"); - if (std::filesystem::exists(notificationsPath)) { - REQUIRE(std::filesystem::remove(notificationsPath)); - } - + RemoveDbFiles(notificationsPath.stem()); NotificationsDB notificationsDb{notificationsPath.c_str()}; REQUIRE(notificationsDb.isInitialized()); @@ -50,11 +47,12 @@ TEST_CASE("Notifications Table tests") REQUIRE(testRow.ID == DB_ID_NONE); REQUIRE(testRow.key == 0); REQUIRE(testRow.value == 0); + REQUIRE(testRow.contactID == DB_ID_NONE); REQUIRE_FALSE(testRow.isValid()); } REQUIRE(notificationsTbl.add({{.ID = 0}, .key = 3, .value = 8})); - REQUIRE(notificationsTbl.add({{.ID = 0}, .key = 4, .value = 16})); + REQUIRE(notificationsTbl.add({{.ID = 0}, .key = 4, .value = 16, .contactID = 100})); REQUIRE(notificationsTbl.count() == 4); @@ -64,6 +62,7 @@ TEST_CASE("Notifications Table tests") REQUIRE(entry.ID == 4); REQUIRE(entry.key == 4); REQUIRE(entry.value == 16); + REQUIRE(entry.contactID == 100); REQUIRE(entry.isValid()); } @@ -73,6 +72,7 @@ TEST_CASE("Notifications Table tests") REQUIRE(entry.ID == 3); REQUIRE(entry.key == 3); REQUIRE(entry.value == 8); + REQUIRE(entry.contactID == DB_ID_NONE); REQUIRE(entry.isValid()); } @@ -93,11 +93,12 @@ TEST_CASE("Notifications Table tests") SECTION("Entry update") { - REQUIRE(notificationsTbl.update({{.ID = 3}, .key = 100, .value = 200})); + REQUIRE(notificationsTbl.update({{.ID = 3}, .key = 100, .value = 200, .contactID = 300})); auto entry = notificationsTbl.getById(3); REQUIRE(entry.ID == 3); REQUIRE(entry.key == 100); REQUIRE(entry.value == 200); + REQUIRE(entry.contactID == 300); } SECTION("Get entry - invalid ID") @@ -107,14 +108,16 @@ TEST_CASE("Notifications Table tests") REQUIRE(entry.ID == DB_ID_NONE); REQUIRE(entry.key == 0); REQUIRE(entry.value == 0); + REQUIRE(entry.ID == DB_ID_NONE); } SECTION("Get by invalid key") { - auto entry = notificationsTbl.getById(100); + auto entry = notificationsTbl.getByKey(100); REQUIRE(entry.ID == DB_ID_NONE); REQUIRE(entry.key == 0); REQUIRE(entry.value == 0); + REQUIRE(entry.ID == DB_ID_NONE); REQUIRE_FALSE(entry.isValid()); } @@ -158,13 +161,14 @@ TEST_CASE("Notifications Table tests") SECTION("Check uniqueness") { - REQUIRE(notificationsTbl.add({{.ID = 0}, .key = 3, .value = 100})); + REQUIRE(notificationsTbl.add({{.ID = 0}, .key = 3, .value = 100, .contactID = 200})); REQUIRE(notificationsTbl.count() == 4); - auto entry = notificationsTbl.getById(3); + auto entry = notificationsTbl.getByKey(3); + REQUIRE(entry.isValid()); REQUIRE(entry.ID == 3); REQUIRE(entry.key == 3); REQUIRE(entry.value == 8); - REQUIRE(entry.isValid()); + REQUIRE(entry.contactID == DB_ID_NONE); } Database::deinitialize(); diff --git a/module-gui/gui/widgets/Style.hpp b/module-gui/gui/widgets/Style.hpp index 674a94a69ec43942c1eb03d98477afade83b2b30..4f844c6243be4876a140028cd99122570685df7b 100644 --- a/module-gui/gui/widgets/Style.hpp +++ b/module-gui/gui/widgets/Style.hpp @@ -249,7 +249,8 @@ namespace style inline constexpr auto spanSize = 8; inline constexpr auto digitSize = 16; inline constexpr auto iconWidth = 35; - inline constexpr auto textMaxWidth = 250; + inline constexpr auto textMinWidth = 250; + inline constexpr auto textMaxWidth = 350; inline constexpr auto itemHeight = 55; namespace model diff --git a/module-services/service-cellular/ServiceCellular.cpp b/module-services/service-cellular/ServiceCellular.cpp index fb3568325b76bd5af60290c9a763598d0c199f12..58758951e2d99b053fdd7cb423c29c1ebda9898e 100644 --- a/module-services/service-cellular/ServiceCellular.cpp +++ b/module-services/service-cellular/ServiceCellular.cpp @@ -214,10 +214,10 @@ ServiceCellular::ServiceCellular() ongoingCall.setEndCallAction([=](const CalllogRecord &rec) { if (DBServiceAPI::CalllogUpdate(this, rec) && rec.type == CallType::CT_MISSED) { - DBServiceAPI::GetQuery( - this, - db::Interface::Name::Notifications, - std::make_unique(NotificationsRecord::Key::Calls)); + DBServiceAPI::GetQuery(this, + db::Interface::Name::Notifications, + std::make_unique( + NotificationsRecord::Key::Calls, rec.phoneNumber)); } return true; }); @@ -1841,21 +1841,23 @@ SMSRecord ServiceCellular::createSMSRecord(const UTF8 &decodedMessage, bool ServiceCellular::dbAddSMSRecord(const SMSRecord &record) { - return DBServiceAPI::AddSMS(this, record, db::QueryCallback::fromFunction([this](auto response) { - auto result = dynamic_cast(response); - if (result == nullptr || !result->result) { - return false; - } - onSMSReceived(); - return true; - })); + return DBServiceAPI::AddSMS( + this, record, db::QueryCallback::fromFunction([this, number = record.number](auto response) { + auto result = dynamic_cast(response); + if (result == nullptr || !result->result) { + return false; + } + onSMSReceived(number); + return true; + })); } -void ServiceCellular::onSMSReceived() +void ServiceCellular::onSMSReceived(const utils::PhoneNumber::View &number) { - DBServiceAPI::GetQuery(this, - db::Interface::Name::Notifications, - std::make_unique(NotificationsRecord::Key::Sms)); + DBServiceAPI::GetQuery( + this, + db::Interface::Name::Notifications, + std::make_unique(NotificationsRecord::Key::Sms, number)); const auto guard = [&]() { return !phoneModeObserver->isInMode(sys::phone_modes::PhoneMode::DoNotDisturb); }; auto filePath = AudioServiceAPI::GetSound(this, audio::PlaybackType::TextMessageRingtone); diff --git a/module-services/service-cellular/service-cellular/ServiceCellular.hpp b/module-services/service-cellular/service-cellular/ServiceCellular.hpp index 98d0bf738ad5b577d1df891ae0546881b4765026..386cad370d0b5be1e33bfb7f9738b293c7b9ab0d 100644 --- a/module-services/service-cellular/service-cellular/ServiceCellular.hpp +++ b/module-services/service-cellular/service-cellular/ServiceCellular.hpp @@ -279,7 +279,7 @@ class ServiceCellular : public sys::Service const time_t messageDate, const SMSType &smsType = SMSType::INBOX) const noexcept; bool dbAddSMSRecord(const SMSRecord &record); - void onSMSReceived(); + void onSMSReceived(const utils::PhoneNumber::View &number); [[nodiscard]] bool receiveAllMessages(); /// @} diff --git a/module-services/service-db/ServiceDB.cpp b/module-services/service-db/ServiceDB.cpp index 939e45d46849f3d783c118d39729fac30df4cc9b..d62c64b54468227ef379a1ce55dfe917de0a3570 100644 --- a/module-services/service-db/ServiceDB.cpp +++ b/module-services/service-db/ServiceDB.cpp @@ -263,7 +263,8 @@ sys::ReturnCodes ServiceDB::InitHandler() notesRecordInterface = std::make_unique(notesDB.get()); calllogRecordInterface = std::make_unique(calllogDB.get(), contactsDB.get()); countryCodeRecordInterface = std::make_unique(countryCodesDB.get()); - notificationsRecordInterface = std::make_unique(notificationsDB.get()); + notificationsRecordInterface = + std::make_unique(notificationsDB.get(), contactRecordInterface.get()); eventsRecordInterface = std::make_unique(eventsDB.get()); quotesRecordInterface = std::make_unique(quotesDB.get()); diff --git a/module-services/service-db/ServiceDB.hpp b/module-services/service-db/ServiceDB.hpp index 2d4489fc7b1967a34b89a77018b5a5a69f0a0d53..c6ef89b0c055d02f98b06d87efcb57f5aa1b6540 100644 --- a/module-services/service-db/ServiceDB.hpp +++ b/module-services/service-db/ServiceDB.hpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include