M changelog.md => changelog.md +1 -0
@@ 6,6 6,7 @@
* Battery Brownout detection
* VoLTE ON/OFF switch in Settings Network window
* Add PLL2 clock switching
+* Support for asynchronous callbacks on application side.
### Changed
M module-apps/Application.cpp => module-apps/Application.cpp +11 -3
@@ 69,8 69,9 @@ namespace app
StartInBackground startInBackground,
uint32_t stackDepth,
sys::ServicePriority priority)
- : Service(name, parent, stackDepth, priority), default_window(gui::name::window::main_window),
- windowsStack(this), startInBackground{startInBackground}, settings(std::make_unique<settings::Settings>(this))
+ : Service(std::move(name), std::move(parent), stackDepth, priority),
+ default_window(gui::name::window::main_window), windowsStack(this), startInBackground{startInBackground},
+ callbackStorage{std::make_unique<CallbackStorage>()}, settings(std::make_unique<settings::Settings>(this))
{
keyTranslator = std::make_unique<gui::KeyInputSimpleTranslation>();
busChannels.push_back(sys::BusChannels::ServiceCellularNotifications);
@@ 85,7 86,10 @@ namespace app
[this](std::string value) { timeFormatChanged(value); });
}
- Application::~Application() = default;
+ Application::~Application() noexcept
+ {
+ windowsStack.windows.clear();
+ }
Application::State Application::getState()
{
@@ 701,4 705,8 @@ namespace app
return timeFormat12;
}
+ void Application::cancelCallbacks(AsyncCallbackReceiver::Ptr receiver)
+ {
+ callbackStorage->removeAll(receiver);
+ }
} /* namespace app */
M module-apps/Application.hpp => module-apps/Application.hpp +10 -2
@@ 3,8 3,10 @@
#pragma once
+#include "AsyncTask.hpp"
#include "Audio/AudioCommon.hpp" // for Volume, Play...
#include "Audio/Profiles/Profile.hpp" // for Profile, Pro...
+#include "CallbackStorage.hpp"
#include "Service/Bus.hpp" // for Bus
#include "Service/Common.hpp" // for ReturnCodes
#include "Service/Message.hpp" // for MessagePointer
@@ 117,7 119,7 @@ namespace app
/// This is template for creating new applications. Main difference between Application and service is that:
/// 1. Application has access to GUI and Input
/// 2. Application lifetime is managed with app::manager::ApplicationManager
- class Application : public sys::Service
+ class Application : public sys::Service, public AsyncCallbacksDeleter
{
public:
/// state in which application is right now
@@ 187,7 189,7 @@ namespace app
uint32_t stackDepth = 4096,
sys::ServicePriority priority = sys::ServicePriority::Idle);
- virtual ~Application();
+ virtual ~Application() noexcept;
Application::State getState();
void setState(State st);
@@ 282,6 284,8 @@ namespace app
void toggleTorch(bsp::torch::ColourTemperature temperature);
+ void cancelCallbacks(AsyncCallbackReceiver::Ptr receiver) override;
+
/// @defgroup Application Application static functions
/// All this functions are meant to be used in ApplicationManager only
/// @note consider moving these as private elements of ApplicationManager i.e. under names
@@ 351,6 355,10 @@ namespace app
/// set of rendering commands will carry information to GUI service that system needs to be closed. After
/// displaying the screen GUI will notify application manager to request system shutdown.
bool shutdownInProgress = false;
+ /// Storage for asynchronous tasks callbacks.
+ std::unique_ptr<CallbackStorage> callbackStorage;
+ friend class AsyncTask; // Async tasks need access to application internals, e.g. callback storage, to make
+ // their API simple.
/// informs self that there was key press
/// used to provide a way for long press/multipress handling in application
A module-apps/AsyncTask.cpp => module-apps/AsyncTask.cpp +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
+
+#include "AsyncTask.hpp"
+#include "Application.hpp"
+
+namespace app
+{
+ AsyncCallbackReceiver::AsyncCallbackReceiver(AsyncCallbacksDeleter *deleter) noexcept : deleter{deleter}
+ {}
+
+ AsyncCallbackReceiver::~AsyncCallbackReceiver()
+ {
+ if (deleter != nullptr) {
+ deleter->cancelCallbacks(this);
+ }
+ }
+
+ void AsyncTask::execute(Application *application, AsyncCallbackReceiver::Ptr receiverObject)
+ {
+ const auto requestId = onExecute(application);
+ application->callbackStorage->registerCallback(requestId, receiverObject);
+ }
+
+ std::unique_ptr<AsyncQuery> AsyncQuery::createFromQuery(std::unique_ptr<db::Query> &&query,
+ db::Interface::Name target)
+ {
+ return std::make_unique<AsyncQuery>(std::move(query), target);
+ }
+
+ AsyncQuery::AsyncQuery(std::unique_ptr<db::Query> &&query, db::Interface::Name target) noexcept
+ : query{std::move(query)}, target{target}
+ {}
+
+ void AsyncQuery::setCallback(std::unique_ptr<db::QueryListener> &&listener) noexcept
+ {
+ query->setQueryListener(std::move(listener));
+ }
+
+ void AsyncQuery::setCallback(db::QueryCallbackFunction &&callback) noexcept
+ {
+ query->setQueryListener(db::QueryCallback::fromFunction(std::move(callback)));
+ }
+
+ RequestId AsyncQuery::onExecute(Application *application)
+ {
+ const auto [_, id] = DBServiceAPI::GetQuery(application, target, std::move(query));
+ return id;
+ }
+
+ auto NullCallback::execute() -> bool
+ {
+ // Nothing to do.
+ return false;
+ }
+
+ QueryCallback::QueryCallback(db::QueryResponse *response) : response{response}
+ {}
+
+ auto QueryCallback::execute() -> bool
+ {
+ const auto result = response->getResult();
+ if (result != nullptr && result->hasListener()) {
+ return result->handle();
+ }
+ return false;
+ }
+} // namespace app
A module-apps/AsyncTask.hpp => module-apps/AsyncTask.hpp +108 -0
@@ 0,0 1,108 @@
+// 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-db/DBServiceAPI.hpp>
+#include <service-db/QueryMessage.hpp>
+
+#include <cstdint>
+
+namespace app
+{
+ class Application; // Forward declaration
+
+ using RequestId = std::uint64_t;
+ class AsyncCallbackReceiver;
+
+ class AsyncCallbacksDeleter
+ {
+ public:
+ virtual ~AsyncCallbacksDeleter() noexcept = default;
+
+ virtual void cancelCallbacks(AsyncCallbackReceiver *receiver) = 0;
+ };
+
+ class AsyncCallbackReceiver
+ {
+ public:
+ using Ptr = AsyncCallbackReceiver *;
+
+ explicit AsyncCallbackReceiver(AsyncCallbacksDeleter *deleter) noexcept;
+ virtual ~AsyncCallbackReceiver() = 0;
+
+ private:
+ AsyncCallbacksDeleter *deleter;
+ };
+
+ /**
+ * Executes an operation on the sender's thread and saves the info about the receiver context for callback use.
+ * Intended to use in order to avoid callbacks called on invalid receiver contexts.
+ */
+ class AsyncTask
+ {
+ public:
+ virtual ~AsyncTask() noexcept = default;
+
+ /**
+ * Executes a task in application's thread and saves the receiver object.
+ * @param application Application
+ * @param receiverObject The context of receiver
+ */
+ void execute(Application *application, AsyncCallbackReceiver::Ptr receiverObject);
+
+ private:
+ /**
+ * The specific operation that is to be executed by a task.
+ * @param application Application
+ * @return Request identifier, to be matched with a response.
+ */
+ [[nodiscard]] virtual auto onExecute(Application *application) -> RequestId = 0;
+ };
+
+ /**
+ * A database query that is using the mechanism of AsyncTask.
+ */
+ class AsyncQuery : public AsyncTask
+ {
+ public:
+ [[nodiscard]] static auto createFromQuery(std::unique_ptr<db::Query> &&query, db::Interface::Name target)
+ -> std::unique_ptr<AsyncQuery>;
+
+ AsyncQuery(std::unique_ptr<db::Query> &&query, db::Interface::Name target) noexcept;
+
+ void setCallback(db::QueryCallbackFunction &&callback) noexcept;
+ void setCallback(std::unique_ptr<db::QueryListener> &&listener) noexcept;
+
+ private:
+ [[nodiscard]] auto onExecute(Application *application) -> RequestId override;
+
+ std::unique_ptr<db::Query> query;
+ db::Interface::Name target;
+ };
+
+ class AsyncCallback
+ {
+ public:
+ virtual ~AsyncCallback() noexcept = default;
+
+ [[nodiscard]] virtual auto execute() -> bool = 0;
+ };
+
+ class NullCallback : public AsyncCallback
+ {
+ public:
+ [[nodiscard]] auto execute() -> bool override;
+ };
+
+ class QueryCallback : public AsyncCallback
+ {
+ public:
+ explicit QueryCallback(db::QueryResponse *response);
+
+ [[nodiscard]] auto execute() -> bool override;
+
+ private:
+ db::QueryResponse *response;
+ };
+} // namespace app
M module-apps/CMakeLists.txt => module-apps/CMakeLists.txt +6 -0
@@ 15,6 15,8 @@ set( SOURCES
"Application.cpp"
"GuiTimer.cpp"
"WindowsFactory.cpp"
+ "AsyncTask.cpp"
+ "CallbackStorage.cpp"
"windows/AppWindow.cpp"
"windows/OptionWindow.cpp"
"windows/Options.cpp"
@@ 156,3 158,7 @@ target_compile_features(${PROJECT_NAME} PUBLIC
cxx_std_14
)
+
+if (${ENABLE_TESTS})
+ add_subdirectory(tests)
+endif()
A module-apps/CallbackStorage.cpp => module-apps/CallbackStorage.cpp +59 -0
@@ 0,0 1,59 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "CallbackStorage.hpp"
+
+#include "MessageType.hpp"
+
+#include <algorithm>
+
+namespace app
+{
+ CallbackStorage::CallbackEntry::CallbackEntry(RequestId id, AsyncCallbackReceiver::Ptr receiver) noexcept
+ : id{id}, receiver{receiver}
+ {}
+
+ auto CallbackStorage::getCallback(sys::ResponseMessage *response) -> std::unique_ptr<AsyncCallback>
+ {
+ if (containsCallbackFor(response)) {
+ remove(response);
+ return toCallback(response);
+ }
+ return std::make_unique<NullCallback>();
+ }
+
+ auto CallbackStorage::containsCallbackFor(sys::ResponseMessage *response) const noexcept -> bool
+ {
+ return std::any_of(
+ entries.begin(), entries.end(), [response](const auto &entry) { return entry->id == response->uniID; });
+ }
+
+ void CallbackStorage::remove(sys::ResponseMessage *response)
+ {
+ const auto it = std::remove_if(
+ entries.begin(), entries.end(), [response](auto &&entry) { return entry->id == response->uniID; });
+ entries.erase(it, entries.end());
+ }
+
+ auto CallbackStorage::toCallback(sys::ResponseMessage *response) -> std::unique_ptr<AsyncCallback>
+ {
+ if (response->responseTo == MessageType::DBQuery) {
+ if (auto queryResponse = dynamic_cast<db::QueryResponse *>(response); queryResponse != nullptr) {
+ return std::make_unique<QueryCallback>(queryResponse);
+ }
+ }
+ return std::make_unique<NullCallback>();
+ }
+
+ void CallbackStorage::registerCallback(RequestId id, AsyncCallbackReceiver::Ptr receiver)
+ {
+ entries.push_back(std::make_unique<CallbackEntry>(id, receiver));
+ }
+
+ void CallbackStorage::removeAll(AsyncCallbackReceiver::Ptr receiver)
+ {
+ const auto it = std::remove_if(
+ entries.begin(), entries.end(), [receiver](const auto &entry) { return entry->receiver == receiver; });
+ entries.erase(it, entries.end());
+ }
+} // namespace app
A module-apps/CallbackStorage.hpp => module-apps/CallbackStorage.hpp +39 -0
@@ 0,0 1,39 @@
+// 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 "AsyncTask.hpp"
+
+#include "module-sys/Service/Message.hpp"
+
+#include <memory>
+#include <list>
+
+namespace app
+{
+ class CallbackStorage
+ {
+ public:
+ [[nodiscard]] auto containsCallbackFor(sys::ResponseMessage *response) const noexcept -> bool;
+ [[nodiscard]] auto getCallback(sys::ResponseMessage *response) -> std::unique_ptr<AsyncCallback>;
+
+ void registerCallback(RequestId id, AsyncCallbackReceiver::Ptr receiver);
+ void removeAll(AsyncCallbackReceiver::Ptr receiver);
+
+ private:
+ [[nodiscard]] static auto toCallback(sys::ResponseMessage *response) -> std::unique_ptr<AsyncCallback>;
+
+ void remove(sys::ResponseMessage *response);
+
+ struct CallbackEntry
+ {
+ public:
+ CallbackEntry(RequestId id, AsyncCallbackReceiver::Ptr receiver) noexcept;
+
+ RequestId id;
+ AsyncCallbackReceiver::Ptr receiver;
+ };
+ std::list<std::unique_ptr<CallbackEntry>> entries;
+ };
+} // namespace app
M module-apps/application-alarm-clock/ApplicationAlarmClock.cpp => module-apps/application-alarm-clock/ApplicationAlarmClock.cpp +2 -11
@@ 51,17 51,8 @@ namespace app
// handle database response
if (resp != nullptr) {
handled = true;
- switch (resp->responseTo) {
- case MessageType::DBQuery: {
- if (auto queryResponse = dynamic_cast<db::QueryResponse *>(resp)) {
- auto result = queryResponse->getResult();
- if (result->hasListener() && result->handle()) {
- refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
- }
- }
- } break;
- default:
- break;
+ if (auto command = callbackStorage->getCallback(resp); command->execute()) {
+ refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
}
}
if (handled) {
M module-apps/application-alarm-clock/models/AlarmsRepository.cpp => module-apps/application-alarm-clock/models/AlarmsRepository.cpp +12 -7
@@ 9,15 9,19 @@
#include <module-db/queries/alarms/QueryAlarmsTurnOffAll.hpp>
#include <service-db/DBServiceAPI.hpp>
+#include "AsyncTask.hpp"
+
namespace app::alarmClock
{
- AlarmsDBRepository::AlarmsDBRepository(Application *application) : application{application}
+ AlarmsDBRepository::AlarmsDBRepository(Application *application)
+ : AsyncCallbackReceiver{application}, application{application}
{}
void AlarmsDBRepository::getLimited(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback)
{
auto query = std::make_unique<db::query::alarms::GetLimited>(offset, limit);
- query->setQueryListener(db::QueryCallback::fromFunction([callback](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Alarms);
+ task->setCallback([callback](auto response) {
auto result = dynamic_cast<db::query::alarms::GetLimitedResult *>(response);
if (result == nullptr) {
return false;
@@ 26,15 30,16 @@ namespace app::alarmClock
callback(result->getResult(), result->getCountResult());
}
return true;
- }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Alarms, std::move(query));
+ });
+ task->execute(application, this);
}
template <class QueryType, class ResultType>
void AlarmsDBRepository::GetQuery(std::unique_ptr<QueryType> query,
const AbstractAlarmsRepository::OnResultCallback &callback)
{
- query->setQueryListener(db::QueryCallback::fromFunction([callback](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Alarms);
+ task->setCallback([callback](auto response) {
auto result = dynamic_cast<ResultType *>(response);
if (result == nullptr) {
return false;
@@ 43,8 48,8 @@ namespace app::alarmClock
callback(result->succeed());
}
return true;
- }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Alarms, std::move(query));
+ });
+ task->execute(application, this);
}
void AlarmsDBRepository::add(const AlarmsRecord &alarm, const AbstractAlarmsRepository::OnResultCallback &callback)
M module-apps/application-alarm-clock/models/AlarmsRepository.hpp => module-apps/application-alarm-clock/models/AlarmsRepository.hpp +1 -1
@@ 23,7 23,7 @@ namespace app::alarmClock
virtual void turnOffAll(const OnResultCallback &callback) = 0;
};
- class AlarmsDBRepository : public AbstractAlarmsRepository
+ class AlarmsDBRepository : public AbstractAlarmsRepository, public AsyncCallbackReceiver
{
public:
explicit AlarmsDBRepository(Application *app);
M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +2 -15
@@ 81,21 81,8 @@ namespace app
// handle database response
if (resp != nullptr) {
handled = true;
- switch (resp->responseTo) {
- case MessageType::DBQuery: {
- if (auto queryResponse = dynamic_cast<db::QueryResponse *>(resp)) {
- auto result = queryResponse->getResult();
- LOG_DEBUG("queryResponse != nullptr");
- if (result->hasListener()) {
- LOG_DEBUG("Has listener");
- if (result->handle()) {
- refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
- }
- }
- }
- } break;
- default:
- break;
+ if (auto command = callbackStorage->getCallback(resp); command->execute()) {
+ refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
}
}
if (handled) {
M module-apps/application-calendar/models/AllEventsModel.cpp => module-apps/application-calendar/models/AllEventsModel.cpp +4 -4
@@ 10,7 10,7 @@
#include <service-db/DBServiceAPI.hpp>
#include <queries/calendar/QueryEventsGetAllLimited.hpp>
-AllEventsModel::AllEventsModel(app::Application *app) : DatabaseModel(app)
+AllEventsModel::AllEventsModel(app::Application *app) : DatabaseModel(app), app::AsyncCallbackReceiver{app}
{
application = app;
assert(app != nullptr);
@@ 24,9 24,9 @@ unsigned int AllEventsModel::requestRecordsCount()
void AllEventsModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
auto query = std::make_unique<db::query::events::GetAllLimited>(offset, limit);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Events, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Events);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
}
unsigned int AllEventsModel::getMinimalItemHeight() const
M module-apps/application-calendar/models/AllEventsModel.hpp => module-apps/application-calendar/models/AllEventsModel.hpp +3 -2
@@ 8,13 8,14 @@
#include <module-db/Interface/EventsRecord.hpp>
#include <module-db/Common/Query.hpp>
-class AllEventsModel : public app::DatabaseModel<EventsRecord>, public gui::ListItemProvider
+class AllEventsModel : public app::DatabaseModel<EventsRecord>,
+ public gui::ListItemProvider,
+ public app::AsyncCallbackReceiver
{
app::Application *application = nullptr;
public:
AllEventsModel(app::Application *app);
- virtual ~AllEventsModel() override = default;
void requestRecords(const uint32_t offset, const uint32_t limit) override;
bool updateRecords(std::vector<EventsRecord> records) override;
M module-apps/application-calendar/models/DayEventsModel.cpp => module-apps/application-calendar/models/DayEventsModel.cpp +5 -4
@@ 11,7 11,8 @@
#include <service-db/QueryMessage.hpp>
#include <module-db/queries/RecordQuery.hpp>
-DayEventsModel::DayEventsModel(app::Application *app) : DatabaseModel(app), application(app)
+DayEventsModel::DayEventsModel(app::Application *app)
+ : DatabaseModel(app), app::AsyncCallbackReceiver{app}, application(app)
{}
unsigned int DayEventsModel::requestRecordsCount()
@@ 27,9 28,9 @@ unsigned int DayEventsModel::getMinimalItemHeight() const
void DayEventsModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
auto query = std::make_unique<db::query::events::GetFiltered>(filterFrom, filterTill, offset, limit);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Events, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Events);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
}
gui::ListItem *DayEventsModel::getItem(gui::Order order)
M module-apps/application-calendar/models/DayEventsModel.hpp => module-apps/application-calendar/models/DayEventsModel.hpp +3 -1
@@ 9,7 9,9 @@
#include <ListItemProvider.hpp>
#include <module-db/Interface/EventsRecord.hpp>
-class DayEventsModel : public app::DatabaseModel<EventsRecord>, public gui::ListItemProvider
+class DayEventsModel : public app::DatabaseModel<EventsRecord>,
+ public gui::ListItemProvider,
+ public app::AsyncCallbackReceiver
{
app::Application *application = nullptr;
std::string dayMonthTitle;
M module-apps/application-calendar/windows/CalendarMainWindow.cpp => module-apps/application-calendar/windows/CalendarMainWindow.cpp +8 -7
@@ 17,7 17,8 @@
namespace gui
{
- CalendarMainWindow::CalendarMainWindow(app::Application *app, const std::string &name) : AppWindow(app, name)
+ CalendarMainWindow::CalendarMainWindow(app::Application *app, const std::string &name)
+ : AppWindow(app, name), app::AsyncCallbackReceiver{app}
{
auto appCalendar = dynamic_cast<app::ApplicationCalendar *>(application);
assert(appCalendar != nullptr);
@@ 185,9 186,9 @@ namespace gui
assert(application != nullptr);
app->setEquivalentToEmptyWindow(EquivalentWindow::AllEventsWindow);
auto query = std::make_unique<db::query::events::GetAll>();
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Events, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Events);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
return true;
}
@@ 202,9 203,9 @@ namespace gui
auto filter_till = TimePointFromYearMonthDay(date_till);
LOG_DEBUG("filter: %s", TimePointToString(filter_till).c_str());
auto query = std::make_unique<db::query::events::GetFiltered>(filter_from, filter_till);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Events, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Events);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
}
auto CalendarMainWindow::handleQueryResponse(db::QueryResult *queryResult) -> bool
M module-apps/application-calendar/windows/CalendarMainWindow.hpp => module-apps/application-calendar/windows/CalendarMainWindow.hpp +1 -2
@@ 22,7 22,7 @@ namespace db
namespace gui
{
- class CalendarMainWindow : public gui::AppWindow
+ class CalendarMainWindow : public gui::AppWindow, public app::AsyncCallbackReceiver
{
bool isDayEmpty[31];
uint32_t offsetFromTop = 0;
@@ 40,7 40,6 @@ namespace gui
public:
CalendarMainWindow(app::Application *app, const std::string &name);
- ~CalendarMainWindow() override = default;
void rebuild() override;
void refresh();
void filterRequest();
M module-apps/application-calllog/ApplicationCallLog.cpp => module-apps/application-calllog/ApplicationCallLog.cpp +2 -2
@@ 135,9 135,9 @@ namespace app
DBServiceAPI::GetQuery(this,
db::Interface::Name::Notifications,
std::make_unique<db::query::notifications::Clear>(NotificationsRecord::Key::Calls));
-
- return DBServiceAPI::GetQuery(
+ const auto [succeed, _] = DBServiceAPI::GetQuery(
this, db::Interface::Name::Calllog, std::make_unique<db::query::calllog::SetAllRead>());
+ return succeed;
}
} /* namespace app */
M module-apps/application-desktop/ApplicationDesktop.cpp => module-apps/application-desktop/ApplicationDesktop.cpp +2 -1
@@ 257,8 257,9 @@ namespace app
bool ApplicationDesktop::requestNotSeenNotifications()
{
- return DBServiceAPI::GetQuery(
+ const auto [succeed, _] = DBServiceAPI::GetQuery(
this, db::Interface::Name::Notifications, std::make_unique<db::query::notifications::GetAll>());
+ return succeed;
}
bool ApplicationDesktop::requestNotReadNotifications()
M module-apps/application-messages/ApplicationMessages.cpp => module-apps/application-messages/ApplicationMessages.cpp +36 -46
@@ 38,7 38,7 @@
namespace app
{
ApplicationMessages::ApplicationMessages(std::string name, std::string parent, StartInBackground startInBackground)
- : Application(name, parent, startInBackground, 4096 * 2)
+ : Application(name, parent, startInBackground, 4096 * 2), AsyncCallbackReceiver{this}
{
busChannels.push_back(sys::BusChannels::ServiceDBNotifications);
addActionReceiver(manager::actions::CreateSms, [this](auto &&data) {
@@ 51,9 51,6 @@ namespace app
});
}
- ApplicationMessages::~ApplicationMessages()
- {}
-
// Invoked upon receiving data message
sys::MessagePointer ApplicationMessages::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
{
@@ 84,26 81,8 @@ namespace app
// handle database response
if (resp != nullptr) {
handled = true;
- switch (resp->responseTo) {
- case MessageType::DBThreadGetLimitOffset:
- [[fallthrough]];
- case MessageType::DBSMSTemplateGetLimitOffset:
- if (getCurrentWindow()->onDatabaseMessage(resp)) {
- refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
- }
- break;
- case MessageType::DBQuery:
- if (auto queryResponse = dynamic_cast<db::QueryResponse *>(resp)) {
- auto result = queryResponse->getResult();
- if (result && result->hasListener()) {
- if (result->handle()) {
- refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
- }
- }
- }
- break;
- default:
- break;
+ if (auto command = callbackStorage->getCallback(resp); command->execute()) {
+ refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
}
}
@@ 193,7 172,8 @@ namespace app
LOG_DEBUG("Removing thread: %" PRIu32, record->ID);
auto query = std::make_unique<ContactGetByID>(record->contactID, true);
- query->setQueryListener(db::QueryCallback::fromFunction([this, record](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Contact);
+ task->setCallback([this, record](auto response) {
auto result = dynamic_cast<ContactGetByIDResult *>(response);
if (result != nullptr) {
const auto &contact = result->getResult();
@@ 206,8 186,9 @@ namespace app
return true;
}
return false;
- }));
- return DBServiceAPI::GetQuery(this, db::Interface::Name::Contact, std::move(query));
+ });
+ task->execute(this, this);
+ return true;
}
bool ApplicationMessages::onRemoveSmsThreadConfirmed(const ThreadRecord &record)
@@ 216,7 197,8 @@ namespace app
using db::query::ThreadRemoveResult;
auto query = std::make_unique<ThreadRemove>(record.ID);
- query->setQueryListener(db::QueryCallback::fromFunction([this, threadId = record.ID](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMSThread);
+ task->setCallback([this, threadId = record.ID](auto response) {
const auto result = dynamic_cast<ThreadRemoveResult *>(response);
if ((result != nullptr) && result->success()) {
switchWindow(gui::name::window::main_window);
@@ 224,12 206,8 @@ namespace app
}
LOG_ERROR("ThreadRemove id=%" PRIu32 " failed", threadId);
return false;
- }));
-
- if (const auto ok = DBServiceAPI::GetQuery(this, db::Interface::Name::SMSThread, std::move(query)); !ok) {
- LOG_ERROR("Unable to query DBServiceAPI");
- return false;
- }
+ });
+ task->execute(this, this);
return true;
}
@@ 255,11 233,13 @@ namespace app
using db::query::ThreadGetByIDResult;
auto query = std::make_unique<SMSRemove>(record.ID);
- query->setQueryListener(db::QueryCallback::fromFunction([this, record](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMS);
+ task->setCallback([this, record](auto response) {
auto result = dynamic_cast<SMSRemoveResult *>(response);
if (result != nullptr && result->getResults()) {
auto query = std::make_unique<ThreadGetByID>(record.threadID);
- query->setQueryListener(db::QueryCallback::fromFunction([this](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMSThread);
+ task->setCallback([this](auto response) {
const auto result = dynamic_cast<ThreadGetByIDResult *>(response);
if (result != nullptr) {
const auto thread = result->getRecord();
@@ 272,14 252,15 @@ namespace app
return true;
}
return false;
- }));
- return DBServiceAPI::GetQuery(this, db::Interface::Name::SMSThread, std::move(query));
+ });
+ task->execute(this, this);
+ return true;
}
LOG_ERROR("sSMSRemove id=%" PRIu32 " failed", record.ID);
return false;
- }));
-
- return DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::move(query));
+ });
+ task->execute(this, this);
+ return true;
}
bool ApplicationMessages::searchEmpty(const std::string &query)
@@ 320,7 301,9 @@ namespace app
record.date = utils::time::getCurrentTimestamp().getTime();
using db::query::SMSUpdate;
- return DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSUpdate>(record));
+ const auto [succeed, _] =
+ DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSUpdate>(record));
+ return succeed;
}
std::pair<SMSRecord, bool> ApplicationMessages::createDraft(const utils::PhoneNumber::View &number,
@@ 335,14 318,17 @@ namespace app
record.date = utils::time::getCurrentTimestamp().getTime();
using db::query::SMSAdd;
- const auto success = DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSAdd>(record));
+ const auto [success, _] =
+ DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSAdd>(record));
return std::make_pair(record, success);
}
bool ApplicationMessages::removeDraft(const SMSRecord &record)
{
using db::query::SMSRemove;
- return DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSRemove>(record.ID));
+ const auto [succeed, _] =
+ DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSRemove>(record.ID));
+ return succeed;
}
bool ApplicationMessages::sendSms(const utils::PhoneNumber::View &number, const UTF8 &body)
@@ 358,7 344,9 @@ namespace app
record.date = utils::time::getCurrentTimestamp().getTime();
using db::query::SMSAdd;
- return DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSAdd>(record));
+ const auto [succeed, _] =
+ DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSAdd>(record));
+ return succeed;
}
bool ApplicationMessages::resendSms(const SMSRecord &record)
@@ 370,7 358,9 @@ namespace app
// the the bottom, but this is correct
using db::query::SMSUpdate;
- return DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSUpdate>(resendRecord));
+ const auto [succeed, _] =
+ DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<SMSUpdate>(resendRecord));
+ return succeed;
}
bool ApplicationMessages::handleSendSmsFromThread(const utils::PhoneNumber::View &number, const UTF8 &body)
M module-apps/application-messages/ApplicationMessages.hpp => module-apps/application-messages/ApplicationMessages.hpp +1 -2
@@ 35,13 35,12 @@ namespace app
inline constexpr auto name_messages = "ApplicationMessages";
- class ApplicationMessages : public app::Application
+ class ApplicationMessages : public app::Application, public app::AsyncCallbackReceiver
{
public:
ApplicationMessages(std::string name = name_messages,
std::string parent = {},
StartInBackground startInBackground = {false});
- virtual ~ApplicationMessages();
sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override;
sys::ReturnCodes InitHandler() override;
M module-apps/application-messages/models/BaseThreadsRecordModel.cpp => module-apps/application-messages/models/BaseThreadsRecordModel.cpp +0 -5
@@ 21,8 21,3 @@ bool BaseThreadsRecordModel::updateRecords(std::vector<ThreadListStruct> records
list->onProviderDataUpdate();
return true;
}
-
-void BaseThreadsRecordModel::requestRecords(uint32_t offset, uint32_t limit)
-{
- DBServiceAPI::ThreadGetLimitOffset(application, offset, limit);
-}
M module-apps/application-messages/models/BaseThreadsRecordModel.hpp => module-apps/application-messages/models/BaseThreadsRecordModel.hpp +0 -1
@@ 33,7 33,6 @@ class BaseThreadsRecordModel : public app::DatabaseModel<ThreadListStruct>, publ
unsigned int requestRecordsCount() override;
bool updateRecords(std::vector<ThreadListStruct> records) override;
- void requestRecords(const uint32_t offset, const uint32_t limit) override;
app::Application *getApplication(void)
{
M module-apps/application-messages/models/SMSTemplateModel.cpp => module-apps/application-messages/models/SMSTemplateModel.cpp +4 -4
@@ 8,7 8,7 @@
#include <service-db/DBServiceAPI.hpp>
#include <module-db/queries/messages/templates/QuerySMSTemplateGetForList.hpp>
-SMSTemplateModel::SMSTemplateModel(app::Application *app) : DatabaseModel(app)
+SMSTemplateModel::SMSTemplateModel(app::Application *app) : DatabaseModel(app), app::AsyncCallbackReceiver{app}
{}
unsigned int SMSTemplateModel::requestRecordsCount()
@@ 56,9 56,9 @@ gui::ListItem *SMSTemplateModel::getItem(gui::Order order)
void SMSTemplateModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
auto query = std::make_unique<db::query::SMSTemplateGetForList>(offset, limit);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::SMSTemplate, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMSTemplate);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
}
auto SMSTemplateModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
M module-apps/application-messages/models/SMSTemplateModel.hpp => module-apps/application-messages/models/SMSTemplateModel.hpp +3 -2
@@ 9,12 9,13 @@
#include <Application.hpp>
#include <ListItemProvider.hpp>
-class SMSTemplateModel : public app::DatabaseModel<SMSTemplateRecord>, public gui::ListItemProvider
+class SMSTemplateModel : public app::DatabaseModel<SMSTemplateRecord>,
+ public gui::ListItemProvider,
+ public app::AsyncCallbackReceiver
{
public:
SMSTemplateModel() = delete;
SMSTemplateModel(app::Application *app);
- virtual ~SMSTemplateModel() = default;
unsigned int requestRecordsCount() override;
bool updateRecords(std::vector<SMSTemplateRecord> records) override;
M module-apps/application-messages/models/SMSThreadModel.cpp => module-apps/application-messages/models/SMSThreadModel.cpp +4 -4
@@ 12,7 12,7 @@
#include "SMSThreadModel.hpp"
#include "ListView.hpp"
-SMSThreadModel::SMSThreadModel(app::Application *app) : DatabaseModel(app)
+SMSThreadModel::SMSThreadModel(app::Application *app) : DatabaseModel(app), app::AsyncCallbackReceiver{app}
{
smsInput = new gui::SMSInputWidget(application);
}
@@ 52,9 52,9 @@ unsigned int SMSThreadModel::requestRecordsCount()
void SMSThreadModel::requestRecords(uint32_t offset, uint32_t limit)
{
auto query = std::make_unique<db::query::SMSGetForList>(smsThreadID, offset, limit, numberID);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::SMS, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMS);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
}
bool SMSThreadModel::updateRecords(std::vector<SMSRecord> records)
M module-apps/application-messages/models/SMSThreadModel.hpp => module-apps/application-messages/models/SMSThreadModel.hpp +3 -1
@@ 9,7 9,9 @@
#include "Interface/SMSRecord.hpp"
#include <application-messages/widgets/SMSInputWidget.hpp>
-class SMSThreadModel : public app::DatabaseModel<SMSRecord>, public gui::ListItemProvider
+class SMSThreadModel : public app::DatabaseModel<SMSRecord>,
+ public gui::ListItemProvider,
+ public app::AsyncCallbackReceiver
{
public:
unsigned int smsThreadID = 0;
M module-apps/application-messages/models/ThreadsModel.cpp => module-apps/application-messages/models/ThreadsModel.cpp +4 -4
@@ 15,7 15,7 @@
#include <module-db/queries/messages/threads/QueryThreadsGetForList.hpp>
#include <service-db/DBServiceAPI.hpp>
-ThreadsModel::ThreadsModel(app::Application *app) : BaseThreadsRecordModel(app)
+ThreadsModel::ThreadsModel(app::Application *app) : BaseThreadsRecordModel(app), app::AsyncCallbackReceiver{app}
{}
auto ThreadsModel::getMinimalItemHeight() const -> unsigned int
@@ 66,9 66,9 @@ auto ThreadsModel::getItem(gui::Order order) -> gui::ListItem *
void ThreadsModel::requestRecords(uint32_t offset, uint32_t limit)
{
auto query = std::make_unique<db::query::ThreadsGetForList>(offset, limit);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(getApplication(), db::Interface::Name::SMSThread, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMSThread);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(getApplication(), this);
}
auto ThreadsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
M module-apps/application-messages/models/ThreadsModel.hpp => module-apps/application-messages/models/ThreadsModel.hpp +1 -1
@@ 6,7 6,7 @@
#include <module-db/Interface/ContactRecord.hpp>
#include "BaseThreadsRecordModel.hpp"
-class ThreadsModel : public BaseThreadsRecordModel
+class ThreadsModel : public BaseThreadsRecordModel, public app::AsyncCallbackReceiver
{
public:
explicit ThreadsModel(app::Application *app);
M module-apps/application-messages/models/ThreadsSearchResultsModel.cpp => module-apps/application-messages/models/ThreadsSearchResultsModel.cpp +5 -4
@@ 14,7 14,8 @@
namespace gui::model
{
- ThreadsSearchResultsModel::ThreadsSearchResultsModel(app::Application *app) : BaseThreadsRecordModel(app)
+ ThreadsSearchResultsModel::ThreadsSearchResultsModel(app::Application *app)
+ : BaseThreadsRecordModel(app), app::AsyncCallbackReceiver{app}
{}
auto ThreadsSearchResultsModel::getMinimalItemHeight() const -> unsigned int
@@ 45,9 46,9 @@ namespace gui::model
{
if (std::string(textToSearch).compare("") != 0) {
auto query = std::make_unique<db::query::ThreadsSearchForList>(textToSearch, offset, limit);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(getApplication(), db::Interface::Name::SMSThread, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMSThread);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
}
}
M module-apps/application-messages/models/ThreadsSearchResultsModel.hpp => module-apps/application-messages/models/ThreadsSearchResultsModel.hpp +1 -1
@@ 9,7 9,7 @@
namespace gui::model
{
- class ThreadsSearchResultsModel : public BaseThreadsRecordModel
+ class ThreadsSearchResultsModel : public BaseThreadsRecordModel, public app::AsyncCallbackReceiver
{
UTF8 textToSearch;
M module-apps/application-messages/windows/MessagesMainWindow.cpp => module-apps/application-messages/windows/MessagesMainWindow.cpp +6 -4
@@ 26,7 26,8 @@
namespace gui
{
- MessagesMainWindow::MessagesMainWindow(app::Application *app) : AppWindow(app, gui::name::window::main_window)
+ MessagesMainWindow::MessagesMainWindow(app::Application *app)
+ : AppWindow(app, gui::name::window::main_window), app::AsyncCallbackReceiver{app}
{
buildInterface();
}
@@ 112,7 113,8 @@ namespace gui
if (pdata != nullptr) {
using db::query::ThreadGetByContactID;
auto query = std::make_unique<ThreadGetByContactID>(pdata->result->ID);
- query->setQueryListener(db::QueryCallback::fromFunction([app = application](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Contact);
+ task->setCallback([app = application](auto response) {
using db::query::ThreadGetByContactIDResult;
const auto result = dynamic_cast<ThreadGetByContactIDResult *>(response);
if ((result != nullptr) && result->getRecord().has_value()) {
@@ 123,8 125,8 @@ namespace gui
}
LOG_FATAL("No thread and thread not created!");
return false;
- }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Contact, std::move(query));
+ });
+ task->execute(application, this);
}
}
M module-apps/application-messages/windows/MessagesMainWindow.hpp => module-apps/application-messages/windows/MessagesMainWindow.hpp +1 -1
@@ 17,7 17,7 @@
namespace gui
{
- class MessagesMainWindow : public AppWindow
+ class MessagesMainWindow : public AppWindow, public app::AsyncCallbackReceiver
{
protected:
Image *leftArrowImage = nullptr;
M module-apps/application-messages/windows/NewMessage.cpp => module-apps/application-messages/windows/NewMessage.cpp +17 -13
@@ 49,7 49,8 @@ namespace gui
std::unique_ptr<NewMessageWindow::MessageMemento> NewMessageWindow::memento =
std::make_unique<NewMessageWindow::MessageMemento>();
- NewMessageWindow::NewMessageWindow(app::Application *app) : AppWindow(app, name::window::new_sms)
+ NewMessageWindow::NewMessageWindow(app::Application *app)
+ : AppWindow(app, name::window::new_sms), app::AsyncCallbackReceiver{app}
{
buildInterface();
}
@@ 311,7 312,8 @@ namespace gui
{
auto number = contactRecord.numbers.front().number;
auto query = std::make_unique<db::query::ThreadGetByContactID>(contactRecord.ID);
- query->setQueryListener(db::QueryCallback::fromFunction([this, number](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMSThread);
+ task->setCallback([this, number](auto response) {
const auto result = dynamic_cast<db::query::ThreadGetByContactIDResult *>(response);
if (result == nullptr) {
return false;
@@ 323,15 325,16 @@ namespace gui
return true;
}
return addDraftToExistingThread(thread->ID, number, message->getText());
- }));
-
- return DBServiceAPI::GetQuery(application, db::Interface::Name::SMSThread, std::move(query));
+ });
+ task->execute(application, this);
+ return true;
}
auto NewMessageWindow::addDraft(const utils::PhoneNumber &number) -> bool
{
auto query = std::make_unique<db::query::ThreadGetByNumber>(number.getView());
- query->setQueryListener(db::QueryCallback::fromFunction([this, number](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMSThread);
+ task->setCallback([this, number](auto response) {
const auto result = dynamic_cast<db::query::ThreadGetByNumberResult *>(response);
if (result == nullptr) {
return false;
@@ 343,9 346,9 @@ namespace gui
return true;
}
return addDraftToExistingThread(thread.ID, number.getView(), message->getText());
- }));
-
- return DBServiceAPI::GetQuery(application, db::Interface::Name::SMSThread, std::move(query));
+ });
+ task->execute(application, this);
+ return true;
}
auto NewMessageWindow::addDraftToExistingThread(unsigned int threadId,
@@ 353,7 356,8 @@ namespace gui
const UTF8 &text) -> bool
{
auto query = std::make_unique<db::query::SMSGetLastByThreadID>(threadId);
- query->setQueryListener(db::QueryCallback::fromFunction([this, number](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::SMS);
+ task->setCallback([this, number](auto response) {
const auto result = dynamic_cast<db::query::SMSGetLastByThreadIDResult *>(response);
if (result == nullptr) {
return false;
@@ 366,9 370,9 @@ namespace gui
}
storeMessageDraft(number, message->getText());
return true;
- }));
-
- return DBServiceAPI::GetQuery(application, db::Interface::Name::SMS, std::move(query));
+ });
+ task->execute(application, this);
+ return true;
}
void NewMessageWindow::storeMessageDraft(const utils::PhoneNumber::View &number, const UTF8 &text)
M module-apps/application-messages/windows/NewMessage.hpp => module-apps/application-messages/windows/NewMessage.hpp +2 -1
@@ 6,6 6,7 @@
#include <chrono>
#include <string>
+#include <AsyncTask.hpp>
#include <AppWindow.hpp>
#include <PhoneNumber.hpp>
#include <widgets/Text.hpp>
@@ 14,7 15,7 @@
namespace gui
{
- class NewMessageWindow : public AppWindow
+ class NewMessageWindow : public AppWindow, public app::AsyncCallbackReceiver
{
public:
explicit NewMessageWindow(app::Application *app);
M module-apps/application-messages/windows/SMSThreadViewWindow.cpp => module-apps/application-messages/windows/SMSThreadViewWindow.cpp +5 -4
@@ 24,7 24,8 @@ namespace gui
{
SMSThreadViewWindow::SMSThreadViewWindow(app::Application *app)
- : AppWindow(app, name::window::thread_view), smsModel{std::make_shared<SMSThreadModel>(this->application)}
+ : AppWindow(app, name::window::thread_view), app::AsyncCallbackReceiver{app},
+ smsModel{std::make_shared<SMSThreadModel>(app)}
{
AppWindow::buildInterface();
setTitle(utils::localize.get("app_messages_title_main"));
@@ 124,9 125,9 @@ namespace gui
auto SMSThreadViewWindow::requestContactName(unsigned int contactID) -> void
{
auto query = std::make_unique<db::query::ContactGetByID>(contactID, true);
- query->setQueryListener(db::QueryCallback::fromFunction(
- [this](auto response) { return handleContactNameQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Contact, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Contact);
+ task->setCallback([this](auto response) { return handleContactNameQueryResponse(response); });
+ task->execute(application, this);
}
auto SMSThreadViewWindow::handleContactNameQueryResponse(db::QueryResult *queryResult) -> bool
M module-apps/application-messages/windows/SMSThreadViewWindow.hpp => module-apps/application-messages/windows/SMSThreadViewWindow.hpp +1 -1
@@ 14,7 14,7 @@
namespace gui
{
- class SMSThreadViewWindow : public AppWindow
+ class SMSThreadViewWindow : public AppWindow, public app::AsyncCallbackReceiver
{
private:
std::shared_ptr<SMSThreadModel> smsModel;
M module-apps/application-notes/ApplicationNotes.cpp => module-apps/application-notes/ApplicationNotes.cpp +2 -12
@@ 56,18 56,8 @@ namespace app
}
if (resp != nullptr) {
- switch (resp->responseTo) {
- case MessageType::DBQuery:
- if (auto queryResponse = dynamic_cast<db::QueryResponse *>(resp); queryResponse != nullptr) {
- if (auto result = queryResponse->getResult(); result && result->hasListener()) {
- if (result->handle()) {
- refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
- }
- }
- }
- break;
- default:
- break;
+ if (auto command = callbackStorage->getCallback(resp); command->execute()) {
+ refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
}
return msgHandled();
}
M module-apps/application-notes/model/NotesRepository.cpp => module-apps/application-notes/model/NotesRepository.cpp +18 -13
@@ 12,13 12,15 @@
namespace app::notes
{
- NotesDBRepository::NotesDBRepository(Application *application) : application{application}
+ NotesDBRepository::NotesDBRepository(Application *application)
+ : app::AsyncCallbackReceiver{application}, application{application}
{}
void NotesDBRepository::get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback)
{
auto query = std::make_unique<db::query::QueryNotesGet>(offset, limit);
- query->setQueryListener(db::QueryCallback::fromFunction([callback](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Notes);
+ task->setCallback([callback](auto response) {
auto result = dynamic_cast<db::query::NotesGetResult *>(response);
if (result == nullptr) {
return false;
@@ 27,14 29,15 @@ namespace app::notes
callback(result->getRecords(), result->getCount());
}
return true;
- }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Notes, std::move(query));
+ });
+ task->execute(application, this);
}
void NotesDBRepository::getByText(const std::string &text, const OnFilteredCallback &callback)
{
auto query = std::make_unique<db::query::QueryNotesGetByText>(text);
- query->setQueryListener(db::QueryCallback::fromFunction([callback](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Notes);
+ task->setCallback([callback](auto response) {
auto result = dynamic_cast<db::query::NotesGetByTextResult *>(response);
if (result == nullptr) {
return false;
@@ 43,14 46,15 @@ namespace app::notes
callback(result->getRecords());
}
return true;
- }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Notes, std::move(query));
+ });
+ task->execute(application, this);
}
void NotesDBRepository::save(const NotesRecord ¬e, const OnResultCallback &callback)
{
auto query = std::make_unique<db::query::QueryNoteStore>(note);
- query->setQueryListener(db::QueryCallback::fromFunction([callback](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Notes);
+ task->setCallback([callback](auto response) {
auto result = dynamic_cast<db::query::NoteStoreResult *>(response);
if (result == nullptr) {
return false;
@@ 59,14 63,15 @@ namespace app::notes
callback(result->succeed());
}
return true;
- }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Notes, std::move(query));
+ });
+ task->execute(application, this);
}
void NotesDBRepository::remove(const NotesRecord ¬e, const OnResultCallback &callback)
{
auto query = std::make_unique<db::query::QueryNoteRemove>(note.ID);
- query->setQueryListener(db::QueryCallback::fromFunction([callback](auto response) {
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Notes);
+ task->setCallback([callback](auto response) {
auto result = dynamic_cast<db::query::NoteRemoveResult *>(response);
if (result == nullptr) {
return false;
@@ 75,7 80,7 @@ namespace app::notes
callback(result->succeed());
}
return true;
- }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Notes, std::move(query));
+ });
+ task->execute(application, this);
}
} // namespace app::notes
M module-apps/application-notes/model/NotesRepository.hpp => module-apps/application-notes/model/NotesRepository.hpp +1 -1
@@ 26,7 26,7 @@ namespace app::notes
virtual void remove(const NotesRecord ¬e, const OnResultCallback &callback) = 0;
};
- class NotesDBRepository : public AbstractNotesRepository
+ class NotesDBRepository : public AbstractNotesRepository, public app::AsyncCallbackReceiver
{
public:
explicit NotesDBRepository(Application *application);
M module-apps/application-phonebook/ApplicationPhonebook.cpp => module-apps/application-phonebook/ApplicationPhonebook.cpp +2 -16
@@ 80,22 80,8 @@ namespace app
// handle database response
if (resp != nullptr) {
handled = true;
- switch (resp->responseTo) {
- case MessageType::DBQuery: {
-
- if (auto queryResponse = dynamic_cast<db::QueryResponse *>(resp)) {
- auto result = queryResponse->getResult();
-
- if (result->hasListener()) {
- if (result->handle()) {
- refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
- }
- }
- }
-
- } break;
- default:
- break;
+ if (auto command = callbackStorage->getCallback(resp); command->execute()) {
+ refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
}
}
M module-apps/application-phonebook/models/PhonebookModel.cpp => module-apps/application-phonebook/models/PhonebookModel.cpp +7 -5
@@ 3,6 3,8 @@
#include <application-phonebook/ApplicationPhonebook.hpp>
#include <application-phonebook/windows/PhonebookContactDetails.hpp>
+#include <AsyncTask.hpp>
+
#include "ListView.hpp"
#include "PhonebookModel.hpp"
@@ 24,8 26,8 @@ PhonebookModel::PhonebookModel(app::Application *app,
std::string filter,
std::uint32_t groupFilter,
std::uint32_t displayMode)
- : DatabaseModel(app), queryFilter(std::move(filter)), queryGroupFilter(std::move(groupFilter)),
- queryDisplayMode(std::move(displayMode))
+ : DatabaseModel(app), app::AsyncCallbackReceiver{app}, queryFilter(std::move(filter)),
+ queryGroupFilter(std::move(groupFilter)), queryDisplayMode(std::move(displayMode))
{}
auto PhonebookModel::requestRecordsCount() -> unsigned int
@@ 60,9 62,9 @@ void PhonebookModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
auto query =
std::make_unique<db::query::ContactGet>(offset, limit, queryFilter, queryGroupFilter, queryDisplayMode);
- query->setQueryListener(
- db::QueryCallback::fromFunction([this](auto response) { return handleQueryResponse(response); }));
- DBServiceAPI::GetQuery(application, db::Interface::Name::Contact, std::move(query));
+ auto task = app::AsyncQuery::createFromQuery(std::move(query), db::Interface::Name::Contact);
+ task->setCallback([this](auto response) { return handleQueryResponse(response); });
+ task->execute(application, this);
}
auto PhonebookModel::requestLetterMap() -> ContactsMapData
M module-apps/application-phonebook/models/PhonebookModel.hpp => module-apps/application-phonebook/models/PhonebookModel.hpp +3 -2
@@ 17,7 17,9 @@
#include <string>
-class PhonebookModel : public app::DatabaseModel<ContactRecord>, public gui::ListItemProvider
+class PhonebookModel : public app::DatabaseModel<ContactRecord>,
+ public gui::ListItemProvider,
+ public app::AsyncCallbackReceiver
{
private:
std::string queryFilter;
@@ 31,7 33,6 @@ class PhonebookModel : public app::DatabaseModel<ContactRecord>, public gui::Lis
std::string filter = "",
std::uint32_t groupFilter = 0,
std::uint32_t displayMode = 0);
- ~PhonebookModel() override = default;
// virtual methods from DatabaseModel
auto updateRecords(std::vector<ContactRecord> records) -> bool override;
M module-apps/application-settings-new/ApplicationSettings.cpp => module-apps/application-settings-new/ApplicationSettings.cpp +1 -1
@@ 96,7 96,7 @@ namespace app
currentWindow->rebuild();
}
}
- else if (auto responseStatusMsg = dynamic_cast<message::bluetooth::ResponseStatus *>(msgl);
+ else if (auto responseStatusMsg = dynamic_cast<::message::bluetooth::ResponseStatus *>(msgl);
nullptr != responseStatusMsg) {
if (gui::window::name::bluetooth == getCurrentWindow()->getName()) {
auto btStatusData = std::make_unique<gui::BluetoothStatusData>(responseStatusMsg->getStatus());
M module-apps/application-settings-new/windows/BluetoothWindow.cpp => module-apps/application-settings-new/windows/BluetoothWindow.cpp +3 -3
@@ 18,7 18,7 @@ namespace gui
topBar->setActive(TopBar::Elements::BATTERY, false);
topBar->setActive(TopBar::Elements::SIM, false);
sys::Bus::SendUnicast(
- std::make_shared<message::bluetooth::RequestStatus>(), service::name::bluetooth, application);
+ std::make_shared<::message::bluetooth::RequestStatus>(), service::name::bluetooth, application);
}
void BluetoothWindow::onBeforeShow(ShowMode mode, SwitchData *data)
@@ 116,10 116,10 @@ namespace gui
btStatus.state = BluetoothStatus::BluetoothState::Off;
}
btStatus.visibility = isPhoneVisibilitySwitchOn;
- message::bluetooth::SetStatus setStatus(btStatus);
+ ::message::bluetooth::SetStatus setStatus(btStatus);
sys::Bus::SendUnicast(
- std::make_shared<message::bluetooth::SetStatus>(setStatus), service::name::bluetooth, application);
+ std::make_shared<::message::bluetooth::SetStatus>(setStatus), service::name::bluetooth, application);
}
void BluetoothWindow::rebuildOptionList()
A module-apps/tests/CMakeLists.txt => module-apps/tests/CMakeLists.txt +9 -0
@@ 0,0 1,9 @@
+add_catch2_executable(
+ NAME
+ callback-storage-test
+ SRCS
+ tests-main.cpp
+ test-CallbackStorage.cpp
+ LIBS
+ ${PROJECT_NAME}
+)
A module-apps/tests/test-CallbackStorage.cpp => module-apps/tests/test-CallbackStorage.cpp +70 -0
@@ 0,0 1,70 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <catch2/catch.hpp>
+
+#include "CallbackStorage.hpp"
+
+#include <functional>
+
+using namespace app;
+
+class TestCallbacksDeleter : public AsyncCallbacksDeleter
+{
+ public:
+ explicit TestCallbacksDeleter(CallbackStorage &storage) : storage{storage}
+ {}
+
+ void cancelCallbacks(AsyncCallbackReceiver *receiver) override
+ {
+ storage.removeAll(receiver);
+ }
+
+ private:
+ CallbackStorage &storage;
+};
+
+class TestReceiver : public AsyncCallbackReceiver
+{
+ public:
+ TestReceiver(TestCallbacksDeleter *deleter = nullptr) : AsyncCallbackReceiver(deleter)
+ {}
+};
+
+TEST_CASE("CallbackStorageTests")
+{
+ CallbackStorage storage;
+
+ SECTION("Get callback")
+ {
+ constexpr auto MessageId = 1;
+ sys::ResponseMessage response{};
+ response.uniID = MessageId;
+
+ TestReceiver receiver;
+ storage.registerCallback(MessageId, &receiver);
+ REQUIRE(storage.containsCallbackFor(&response));
+
+ [[maybe_unused]] auto callback = storage.getCallback(&response);
+ REQUIRE(!storage.containsCallbackFor(&response));
+ }
+
+ SECTION("Remove receiver")
+ {
+ constexpr auto MessageId = 2;
+ sys::ResponseMessage response{};
+ response.uniID = MessageId;
+
+ {
+ TestCallbacksDeleter deleter{storage};
+ TestReceiver receiver{&deleter};
+
+ storage.registerCallback(MessageId, &receiver);
+ REQUIRE(storage.containsCallbackFor(&response));
+ }
+
+ REQUIRE(!storage.containsCallbackFor(&response));
+ [[maybe_unused]] auto callback = storage.getCallback(&response);
+ REQUIRE(callback->execute() == false);
+ }
+}
A module-apps/tests/tests-main.cpp => module-apps/tests/tests-main.cpp +5 -0
@@ 0,0 1,5 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
+#include <catch2/catch.hpp>
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +2 -1
@@ 1820,7 1820,8 @@ bool ServiceCellular::dbAddSMSRecord(const SMSRecord &record)
onSMSReceived();
return true;
}));
- return DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::move(query));
+ const auto [succeed, _] = DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::move(query));
+ return succeed;
}
void ServiceCellular::onSMSReceived()
M module-services/service-db/DBServiceAPI.cpp => module-services/service-db/DBServiceAPI.cpp +0 -11
@@ 54,17 54,6 @@ auto DBServiceAPI::ThreadGetByNumber(sys::Service *serv,
return nullptr;
}
-auto DBServiceAPI::ThreadGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit) -> bool
-{
- std::shared_ptr<DBThreadMessage> msg = std::make_shared<DBThreadMessage>(MessageType::DBThreadGetLimitOffset);
- msg->offset = offset;
- msg->limit = limit;
-
- sys::Bus::SendUnicast(msg, service::name::db, serv);
-
- return true;
-}
-
auto DBServiceAPI::ThreadGetCount(sys::Service *serv, EntryState state) -> uint32_t
{
auto msg = std::make_shared<DBThreadGetCountMessage>(state);
M module-services/service-db/DBServiceAPI_GetByQuery.cpp => module-services/service-db/DBServiceAPI_GetByQuery.cpp +5 -2
@@ 22,10 22,13 @@ namespace sys
class Service;
} // namespace sys
-bool DBServiceAPI::GetQuery(sys::Service *serv, db::Interface::Name database, std::unique_ptr<db::Query> query)
+std::pair<bool, std::uint64_t> DBServiceAPI::GetQuery(sys::Service *serv,
+ db::Interface::Name database,
+ std::unique_ptr<db::Query> query)
{
auto msg = std::make_shared<db::QueryMessage>(database, std::move(query));
- return sys::Bus::SendUnicast(msg, service::name::db, serv);
+ const auto isSuccess = sys::Bus::SendUnicast(msg, service::name::db, serv);
+ return std::make_pair(isSuccess, msg->uniID);
}
sys::SendResult DBServiceAPI::GetQueryWithReply(sys::Service *serv,
M module-services/service-db/ServiceDB.cpp => module-services/service-db/ServiceDB.cpp +0 -9
@@ 209,15 209,6 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
sendUpdateNotification(db::Interface::Name::SMSThread, db::Query::Type::Delete);
} break;
- case MessageType::DBThreadGetLimitOffset: {
- auto time = utils::time::Scoped("DBThreadGetLimitOffset");
- DBThreadMessage *msg = reinterpret_cast<DBThreadMessage *>(msgl);
- auto ret = threadRecordInterface->GetLimitOffset(msg->offset, msg->limit);
- LOG_INFO("Thread get limit offset");
- responseMsg =
- std::make_shared<DBThreadResponseMessage>(std::move(ret), true, msg->limit, msg->offset, ret->size());
- } break;
-
case MessageType::DBThreadGetCount: {
auto *msg = static_cast<DBThreadGetCountMessage *>(msgl);
auto time = utils::time::Scoped("DBThreadGetCountMessage");
M module-services/service-db/service-db/DBServiceAPI.hpp => module-services/service-db/service-db/DBServiceAPI.hpp +10 -2
@@ 52,10 52,18 @@ class DBServiceAPI
static auto ThreadGetByNumber(sys::Service *serv,
const utils::PhoneNumber::View &phoneNumber,
std::uint32_t timeout = DefaultTimeoutInMs) -> std::unique_ptr<ThreadRecord>;
- static auto ThreadGetLimitOffset(sys::Service *serv, uint32_t offset, uint32_t limit) -> bool;
static auto ThreadGetCount(sys::Service *serv, EntryState state = EntryState::ALL) -> uint32_t;
- static auto GetQuery(sys::Service *serv, db::Interface::Name database, std::unique_ptr<db::Query> query) -> bool;
+ /**
+ * Queries the database.
+ * @param serv Sender service.
+ * @param database Target database name.
+ * @param query Query.
+ * @return A pair of: a flag that indicates whether query send was successful, and a message identifier that common
+ * for the query and its response.
+ */
+ static auto GetQuery(sys::Service *serv, db::Interface::Name database, std::unique_ptr<db::Query> query)
+ -> std::pair<bool, std::uint64_t>;
static auto GetQueryWithReply(sys::Service *serv,
db::Interface::Name database,
std::unique_ptr<db::Query> query,
M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp +8 -4
@@ 184,7 184,7 @@ auto CalendarEventsHelper::requestDataFromDB(Context &context) -> sys::ReturnCod
context);
query->setQueryListener(std::move(listener));
- auto ret = DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ auto [ret, _] = DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
if (ret) {
return sys::ReturnCodes::Success;
@@ 280,7 280,9 @@ auto CalendarEventsHelper::createDBEntry(Context &context) -> sys::ReturnCodes
context);
query->setQueryListener(std::move(listener));
- ret = ret && DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ const auto [succeed, _] =
+ DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ ret = ret && succeed;
}
if (ret) {
@@ 315,7 317,9 @@ auto CalendarEventsHelper::updateDBEntry(Context &context) -> sys::ReturnCodes
context);
query->setQueryListener(std::move(listener));
- ret = ret && DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ const auto [succeed, _] =
+ DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ ret = ret && succeed;
}
if (ret) {
return sys::ReturnCodes::Success;
@@ 341,7 345,7 @@ auto CalendarEventsHelper::deleteDBEntry(Context &context) -> sys::ReturnCodes
context);
query->setQueryListener(std::move(listener));
- auto ret = DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
+ auto [ret, _] = DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
if (ret) {
return sys::ReturnCodes::Success;
M module-services/service-time/timeEvents/CalendarTimeEvents.cpp => module-services/service-time/timeEvents/CalendarTimeEvents.cpp +7 -4
@@ 43,9 43,11 @@ namespace stm
filterTill = filterFrom;
}
- return DBServiceAPI::GetQuery(service(),
- db::Interface::Name::Events,
- std::make_unique<db::query::events::SelectFirstUpcoming>(filterFrom, filterTill));
+ const auto [succeed, _] =
+ DBServiceAPI::GetQuery(service(),
+ db::Interface::Name::Events,
+ std::make_unique<db::query::events::SelectFirstUpcoming>(filterFrom, filterTill));
+ return succeed;
}
uint32_t CalendarTimeEvents::calcToNextEventInterval(std::unique_ptr<db::QueryResult> nextEventQueryResult)
@@ 74,8 76,9 @@ namespace stm
bool CalendarTimeEvents::sendEventFiredQuery()
{
eventRecord.reminder_fired = TimePointNow();
- return DBServiceAPI::GetQuery(
+ const auto [succeed, _] = DBServiceAPI::GetQuery(
service(), db::Interface::Name::Events, std::make_unique<db::query::events::Edit>(eventRecord));
+ return succeed;
}
void CalendarTimeEvents::invokeEvent()