M products/BellHybrid/apps/application-bell-whats-new/ApplicationWhatsNew.cpp => products/BellHybrid/apps/application-bell-whats-new/ApplicationWhatsNew.cpp +1 -1
@@ 33,7 33,7 @@ namespace app
return ret;
}
- whatsNewModel = std::make_unique<whatsNew::models::WhatsNewModel>();
+ whatsNewModel = std::make_unique<whatsNew::models::WhatsNewModel>(this);
batteryModel = std::make_unique<app::BatteryModel>(this);
lowBatteryInfoModel = std::make_unique<app::LowBatteryInfoModel>();
M products/BellHybrid/apps/application-bell-whats-new/models/WhatsNewModel.cpp => products/BellHybrid/apps/application-bell-whats-new/models/WhatsNewModel.cpp +55 -2
@@ 2,10 2,63 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "WhatsNewModel.hpp"
+#include <ApplicationCommon.hpp>
+#include <db/ServiceDB.hpp>
+#include <db/WhatsNewMessages.hpp>
+#include <product/version.hpp>
+#include <Utils.hpp>
+
+namespace
+{
+ using namespace service::db::whatsNew;
+ constexpr auto versionSize{3U};
+
+ std::optional<VersionNumber> getVersionNumber(std::string version)
+ {
+ std::vector<std::string> strVector{utils::split(version, '.')};
+ if (strVector.size() != versionSize) {
+ return std::nullopt;
+ }
+
+ std::vector<std::uint16_t> uintVector{};
+ uintVector.reserve(versionSize);
+
+ for (auto &str : strVector) {
+ if (!utils::is_number(str)) {
+ return std::nullopt;
+ }
+ uintVector.push_back(utils::getNumericValue<std::uint16_t>(str));
+ }
+ return VersionNumber{.major{uintVector[0]}, .minor{uintVector[1]}, .patch{uintVector[2]}};
+ }
+
+ std::optional<messages::Response> sendDBRequest(sys::Service *serv, std::shared_ptr<sys::Message> &&msg)
+ {
+ const auto ret = serv->bus.sendUnicastSync(std::move(msg), service::name::db, sys::BusProxy::defaultTimeout);
+ if (ret.first == sys::ReturnCodes::Success) {
+ if (auto resp = std::dynamic_pointer_cast<messages::Response>(ret.second)) {
+ return *resp;
+ }
+ }
+ return std::nullopt;
+ }
+} // namespace
namespace app::whatsNew::models
{
- WhatsNewModel::WhatsNewModel()
- {}
+ WhatsNewModel::WhatsNewModel(app::ApplicationCommon *app) : app{app}
+ {
+ const auto version = getVersionNumber(VERSION);
+ if (!version.has_value()) {
+ return;
+ }
+ const auto result = sendDBRequest(app, std::make_shared<messages::GetByVersion>(version.value()));
+ if (result.has_value()) {
+ for (auto &record : result->records) {
+ LOG_ERROR("*** changes: %s iconName: %s ***", record.description.c_str(), record.iconName.c_str());
+ features.push_back({.description = record.description, .iconName = record.iconName});
+ }
+ }
+ }
} // namespace app::whatsNew::models
M products/BellHybrid/apps/application-bell-whats-new/models/WhatsNewModel.hpp => products/BellHybrid/apps/application-bell-whats-new/models/WhatsNewModel.hpp +19 -1
@@ 3,11 3,29 @@
#pragma once
+#include <string>
+#include <vector>
+
+namespace app
+{
+ class ApplicationCommon;
+}
+
namespace app::whatsNew::models
{
+ struct Feature
+ {
+ const std::string description;
+ const std::string iconName;
+ };
+
class WhatsNewModel
{
public:
- WhatsNewModel();
+ explicit WhatsNewModel(app::ApplicationCommon *app);
+
+ private:
+ app::ApplicationCommon *app{nullptr};
+ std::vector<Feature> features;
};
} // namespace app::whatsNew::models
M products/BellHybrid/services/db/CMakeLists.txt => products/BellHybrid/services/db/CMakeLists.txt +2 -0
@@ 10,8 10,10 @@ target_sources(databases
agents/MeditationStatsAgent.cpp
agents/QuotesAgent.cpp
agents/ShuffleQuoteModel.cpp
+ agents/WhatsNewAgent.cpp
agents/QuotesAgent.hpp
agents/ShuffleQuoteModel.hpp
+ agents/WhatsNewAgent.hpp
PUBLIC
include/db/ServiceDB.hpp
include/db/SystemSettings.hpp
M products/BellHybrid/services/db/ServiceDB.cpp => products/BellHybrid/services/db/ServiceDB.cpp +18 -6
@@ 1,10 1,11 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include <db/ServiceDB.hpp>
+#include "include/db/ServiceDB.hpp"
#include <db/BellFactorySettings.hpp>
#include "agents/MeditationStatsAgent.hpp"
+#include "agents/WhatsNewAgent.hpp"
#include <module-db/databases/EventsDB.hpp>
#include <module-db/databases/MultimediaFilesDB.hpp>
@@ 21,6 22,16 @@
#include <CrashdumpMetadataStore.hpp>
#include <product/version.hpp>
+namespace
+{
+ constexpr auto eventsDatabaseName{"events.db"};
+ constexpr auto quotesDatabaseName{"quotes.db"};
+ constexpr auto multimediaDatabaseName{"multimedia.db"};
+ constexpr auto settingsDatabaseName{"settings_bell.db"};
+ constexpr auto meditationStatsDatabaseName{"meditation_stats.db"};
+ constexpr auto whatsNewDatabaseName{"whats-new.db"};
+} // namespace
+
ServiceDB::~ServiceDB()
{
eventsDB.reset();
@@ 52,10 63,10 @@ sys::ReturnCodes ServiceDB::InitHandler()
}
// Create databases
- eventsDB = std::make_unique<EventsDB>((purefs::dir::getDatabasesPath() / "events.db").c_str());
- quotesDB = std::make_unique<Database>((purefs::dir::getDatabasesPath() / "quotes.db").c_str());
+ eventsDB = std::make_unique<EventsDB>((purefs::dir::getDatabasesPath() / eventsDatabaseName).c_str());
+ quotesDB = std::make_unique<Database>((purefs::dir::getDatabasesPath() / quotesDatabaseName).c_str());
multimediaFilesDB = std::make_unique<db::multimedia_files::MultimediaFilesDB>(
- (purefs::dir::getDatabasesPath() / "multimedia.db").c_str());
+ (purefs::dir::getDatabasesPath() / multimediaDatabaseName).c_str());
// Create record interfaces
alarmEventRecordInterface = std::make_unique<AlarmEventRecordInterface>(eventsDB.get());
@@ 63,8 74,9 @@ sys::ReturnCodes ServiceDB::InitHandler()
std::make_unique<db::multimedia_files::MultimediaFilesRecordInterface>(multimediaFilesDB.get());
const auto factorySettings = std::make_unique<settings::BellFactorySettings>();
- databaseAgents.emplace(std::make_unique<SettingsAgent>(this, "settings_bell.db", factorySettings.get()));
- databaseAgents.emplace(std::make_unique<service::db::agents::MeditationStats>(this, "meditation_stats.db"));
+ databaseAgents.emplace(std::make_unique<SettingsAgent>(this, settingsDatabaseName, factorySettings.get()));
+ databaseAgents.emplace(std::make_unique<service::db::agents::MeditationStats>(this, meditationStatsDatabaseName));
+ databaseAgents.emplace(std::make_unique<service::db::agents::WhatsNew>(this, whatsNewDatabaseName));
for (auto &dbAgent : databaseAgents) {
dbAgent->registerMessages();
A products/BellHybrid/services/db/agents/WhatsNewAgent.cpp => products/BellHybrid/services/db/agents/WhatsNewAgent.cpp +74 -0
@@ 0,0 1,74 @@
+// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "WhatsNewAgent.hpp"
+#include "db/WhatsNewMessages.hpp"
+
+#include <Service/Service.hpp>
+#include <purefs/filesystem_paths.hpp>
+#include <i18n/i18n.hpp>
+
+namespace
+{
+ using namespace service::db::whatsNew;
+
+ constexpr auto query = "SELECT %s, Icon FROM WhatsNew WHERE Major > %d OR (Major = %d AND Minor > %d) OR (Major = "
+ "%d AND Minor = %d AND Patch > %d)";
+
+ std::vector<Record> getRecordsByVersion(Database *db, VersionNumber version)
+ {
+ const auto retQuery = db->query(query,
+ utils::getDisplayLanguage().c_str(),
+ version.major,
+ version.major,
+ version.minor,
+ version.major,
+ version.minor,
+ version.patch);
+
+ if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
+ return {};
+ }
+
+ std::vector<Record> ret;
+ ret.reserve(retQuery->getRowCount());
+
+ do {
+ ret.push_back({.description{(*retQuery)[0].getString()}, .iconName{(*retQuery)[1].getString()}});
+ } while (retQuery->nextRow());
+
+ return ret;
+ }
+} // namespace
+
+namespace service::db::agents
+{
+ WhatsNew::WhatsNew(sys::Service *parentService, const std::string dbName)
+ : DatabaseAgent{parentService}, dbName{dbName}, db{(purefs::dir::getDatabasesPath() / dbName).c_str()}
+ {}
+
+ void WhatsNew::registerMessages()
+ {
+ parentService->connect(whatsNew::messages::GetByVersion({}),
+ [this](const auto &req) { return handleGetRecordsByVersion(req); });
+ }
+
+ void WhatsNew::unRegisterMessages()
+ {
+ parentService->disconnect(typeid(whatsNew::messages::GetByVersion));
+ }
+
+ auto WhatsNew::getAgentName() -> const std::string
+ {
+ return dbName + "_agent";
+ }
+
+ sys::MessagePointer WhatsNew::handleGetRecordsByVersion(const sys::Message *req)
+ {
+ if (auto msg = dynamic_cast<const whatsNew::messages::GetByVersion *>(req)) {
+ const auto records = getRecordsByVersion(&db, msg->version);
+ return std::make_shared<whatsNew::messages::Response>(records);
+ }
+ return std::make_shared<sys::ResponseMessage>();
+ }
+} // namespace service::db::agents<
\ No newline at end of file
A products/BellHybrid/services/db/agents/WhatsNewAgent.hpp => products/BellHybrid/services/db/agents/WhatsNewAgent.hpp +34 -0
@@ 0,0 1,34 @@
+// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <service-db/DatabaseAgent.hpp>
+#include <module-services/service-db/include/service-db/SettingsMessages.hpp>
+#include <module-sys/Service/include/Service/Message.hpp>
+
+#include <string>
+
+namespace sys
+{
+ class Service;
+} // namespace sys
+
+namespace service::db::agents
+{
+ class WhatsNew : public DatabaseAgent
+ {
+ public:
+ WhatsNew(sys::Service *parentService, std::string dbName);
+
+ void registerMessages() override;
+ void unRegisterMessages() override;
+ auto getAgentName() -> const std::string override;
+
+ private:
+ sys::MessagePointer handleGetRecordsByVersion(const sys::Message *req);
+
+ std::string dbName;
+ Database db;
+ };
+} // namespace service::db::agents
A products/BellHybrid/services/db/include/db/WhatsNewMessages.hpp => products/BellHybrid/services/db/include/db/WhatsNewMessages.hpp +44 -0
@@ 0,0 1,44 @@
+// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <MessageType.hpp>
+#include <Service/Message.hpp>
+#include <vector>
+
+namespace service::db::whatsNew
+{
+ struct Record
+ {
+ std::string description;
+ std::string iconName;
+ };
+
+ struct VersionNumber
+ {
+ std::uint16_t major;
+ std::uint16_t minor;
+ std::uint16_t patch;
+ };
+
+ namespace messages
+ {
+ struct GetByVersion : public sys::DataMessage
+ {
+ explicit GetByVersion(VersionNumber version) : version{version}
+ {}
+ VersionNumber version;
+ };
+
+ struct Response : public sys::ResponseMessage
+ {
+ Response() = default;
+ explicit Response(const std::vector<Record> &records) : records{records}
+ {}
+
+ std::vector<Record> records{};
+ };
+
+ } // namespace messages
+} // namespace service::db::whatsNew<
\ No newline at end of file