Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorenricoturri1966 <enricoturri@seznam.cz>2020-12-03 17:12:32 +0300
committerenricoturri1966 <enricoturri@seznam.cz>2020-12-03 17:12:32 +0300
commitbcb2a4884b1e119907bc6898e01f4b8f094e9137 (patch)
tree5ede4f30b3f9ee19bca2b549f1480e0cb0bfde85 /src/slic3r
parent42a00a32dfbd58cb07c672f8c39d644fc6949b44 (diff)
NotificationManager -> Separate notification update from its render to reduce the amount of scene refresh
Diffstat (limited to 'src/slic3r')
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp24
-rw-r--r--src/slic3r/GUI/NotificationManager.cpp242
-rw-r--r--src/slic3r/GUI/NotificationManager.hpp61
3 files changed, 314 insertions, 13 deletions
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index e2d3a9585..84b17efb7 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1703,7 +1703,7 @@ void GLCanvas3D::render()
m_tooltip.render(m_mouse.position, *this);
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
- wxGetApp().plater()->get_notification_manager()->render_notifications(get_overlay_window_width());
+ wxGetApp().plater()->get_notification_manager()->render_notifications(get_overlay_window_width());
wxGetApp().imgui()->render();
@@ -2358,6 +2358,14 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
if (!m_initialized)
return;
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ NotificationManager* notification_mgr = wxGetApp().plater()->get_notification_manager();
+ if (notification_mgr->requires_update())
+ notification_mgr->update_notifications();
+
+ m_dirty |= notification_mgr->requires_render();
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+
m_dirty |= m_main_toolbar.update_items_state();
m_dirty |= m_undoredo_toolbar.update_items_state();
m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
@@ -2365,12 +2373,24 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
m_dirty |= mouse3d_controller_applied;
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ if (!m_dirty) {
+ if (notification_mgr->requires_update())
+ evt.RequestMore();
+ return;
+ }
+#else
if (!m_dirty)
return;
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
_refresh_if_shown_on_screen();
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ if (m_extra_frame_requested || mouse3d_controller_applied || notification_mgr->requires_update()) {
+#else
if (m_extra_frame_requested || mouse3d_controller_applied) {
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
m_dirty = true;
m_extra_frame_requested = false;
evt.RequestMore();
@@ -2505,7 +2525,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case WXK_BACK:
case WXK_DELETE:
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); break;
- default: evt.Skip();
+ default: evt.Skip();
}
}
else if ((evt.GetModifiers() & shiftMask) != 0) {
diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp
index 15c84af9e..bf4142b9c 100644
--- a/src/slic3r/GUI/NotificationManager.cpp
+++ b/src/slic3r/GUI/NotificationManager.cpp
@@ -18,6 +18,9 @@
static constexpr float GAP_WIDTH = 10.0f;
static constexpr float SPACE_RIGHT_PANEL = 10.0f;
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+static constexpr float FADING_OUT_DURATION = 2.0f;
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
namespace Slic3r {
namespace GUI {
@@ -134,6 +137,96 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n,
{
//init();
}
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width)
+{
+ if (m_hidden) {
+ m_top_y = initial_y - GAP_WIDTH;
+ return;
+ }
+
+ Size cnv_size = canvas.get_canvas_size();
+ ImGuiWrapper& imgui = *wxGetApp().imgui();
+ ImVec2 mouse_pos = ImGui::GetMousePos();
+ float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0);
+
+ if (m_line_height != ImGui::CalcTextSize("A").y)
+ init();
+
+ set_next_window_size(imgui);
+
+ // top y of window
+ m_top_y = initial_y + m_window_height;
+
+ ImVec2 win_pos(1.0f * (float)cnv_size.get_width() - right_gap, 1.0f * (float)cnv_size.get_height() - m_top_y);
+ imgui.set_next_window_pos(win_pos.x, win_pos.y, ImGuiCond_Always, 1.0f, 0.0f);
+ imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always);
+
+ // find if hovered
+ m_hovered = false;
+ if (mouse_pos.x < win_pos.x && mouse_pos.x > win_pos.x - m_window_width && mouse_pos.y > win_pos.y && mouse_pos.y < win_pos.y + m_window_height) {
+ ImGui::SetNextWindowFocus();
+ m_hovered = true;
+ }
+
+ // color change based on fading out
+ bool fading_pop = false;
+ if (m_fading_out) {
+ Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity);
+ Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), m_fading_out, m_current_fade_opacity);
+ fading_pop = true;
+ }
+
+ // background color
+ if (m_is_gray) {
+ ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
+ Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
+ }
+ else if (m_data.level == NotificationLevel::ErrorNotification) {
+ ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
+ backcolor.x += 0.3f;
+ Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
+ }
+ else if (m_data.level == NotificationLevel::WarningNotification) {
+ ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
+ backcolor.x += 0.3f;
+ backcolor.y += 0.15f;
+ Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
+ }
+
+ // name of window - probably indentifies window and is shown so last_end add whitespaces according to id
+ if (m_id == 0)
+ m_id = m_id_provider.allocate_id();
+ std::string name = "!!Ntfctn" + std::to_string(m_id);
+ if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar)) {
+ ImVec2 win_size = ImGui::GetWindowSize();
+
+ //FIXME: dont forget to us this for texts
+ //GUI::format(_utf8(L()));
+
+ /*
+ //countdown numbers
+ ImGui::SetCursorPosX(15);
+ ImGui::SetCursorPosY(15);
+ imgui.text(std::to_string(m_remaining_time).c_str());
+ */
+
+ render_left_sign(imgui);
+ render_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
+ render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
+ m_minimize_b_visible = false;
+ if (m_multiline && m_lines_count > 3)
+ render_minimize_button(imgui, win_pos.x, win_pos.y);
+ }
+ imgui.end();
+
+ if (m_is_gray || m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification)
+ ImGui::PopStyleColor();
+
+ if (fading_pop)
+ ImGui::PopStyleColor(2);
+}
+#else
NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width)
{
if (!m_initialized) {
@@ -268,6 +361,7 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif
ImGui::PopStyleColor();
return ret_val;
}
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::count_spaces()
{
//determine line width
@@ -528,6 +622,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
+#if !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::render_countdown(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
/*
@@ -575,6 +670,7 @@ void NotificationManager::PopNotification::render_countdown(ImGuiWrapper& imgui,
m_countdown_frame++;
*/
}
+#endif // !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::render_left_sign(ImGuiWrapper& imgui)
{
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
@@ -643,6 +739,52 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text)
return false;
}
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+void NotificationManager::PopNotification::update_state()
+{
+ if (!m_initialized)
+ init();
+
+ if (m_hidden) {
+ m_state = EState::Static;
+ return;
+ }
+
+ if (m_hovered) {
+ // reset fading
+ m_fading_out = false;
+ m_current_fade_opacity = 1.0f;
+ m_remaining_time = m_data.duration;
+ }
+
+ if (m_counting_down) {
+ if (m_fading_out && m_current_fade_opacity <= 0.0f)
+ m_finished = true;
+ else if (!m_fading_out && m_remaining_time == 0) {
+ m_fading_out = true;
+ m_fading_start = wxGetLocalTimeMillis();
+ }
+ }
+
+ if (m_finished) {
+ m_state = EState::Finished;
+ return;
+ }
+ if (m_close_pending) {
+ m_finished = true;
+ m_state = EState::ClosePending;
+ return;
+ }
+ if (m_fading_out) {
+ if (!m_paused) {
+ wxMilliClock_t curr_time = wxGetLocalTimeMillis() - m_fading_start;
+ m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast<float>(curr_time.GetValue()) / FADING_OUT_DURATION, 0.0f, 1.0f);
+ }
+ m_state = EState::FadingOut;
+ }
+}
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+
NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) :
NotificationManager::PopNotification(n, id_provider, evt_handler)
{
@@ -1031,6 +1173,10 @@ bool NotificationManager::push_notification_data(const NotificationData& notific
}
bool NotificationManager::push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp)
{
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ m_requires_update = true;
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+
// if timestamped notif, push only new one
if (timestamp != 0) {
if (m_used_timestamps.find(timestamp) == m_used_timestamps.end()) {
@@ -1052,6 +1198,21 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan
return true;
}
}
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+void NotificationManager::render_notifications(float overlay_width)
+{
+ sort_notifications();
+
+ GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D();
+ float last_y = 0.0f;
+
+ for (const auto& notification : m_pop_notifications) {
+ notification->render(canvas, last_y, m_move_from_overlay && !m_in_preview, overlay_width);
+ if (notification->get_state() != PopNotification::EState::Finished)
+ last_y = notification->get_top() + GAP_WIDTH;
+ }
+}
+#else
void NotificationManager::render_notifications(float overlay_width)
{
float last_x = 0.0f;
@@ -1063,9 +1224,9 @@ void NotificationManager::render_notifications(float overlay_width)
GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D();
- // iterate thru notifications and render them / erease them
+ // iterate thru notifications and render them / erase them
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
- if ((*it)->get_finished()) {
+ if ((*it)->is_finished()) {
it = m_pop_notifications.erase(it);
} else {
(*it)->set_paused(m_hovered);
@@ -1115,6 +1276,7 @@ void NotificationManager::render_notifications(float overlay_width)
// If any of the notifications is fading out, 100% of the CPU/GPU is consumed.
canvas.request_extra_frame();
}
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::sort_notifications()
{
@@ -1122,7 +1284,7 @@ void NotificationManager::sort_notifications()
std::stable_sort(m_pop_notifications.begin(), m_pop_notifications.end(), [](const std::unique_ptr<PopNotification> &n1, const std::unique_ptr<PopNotification> &n2) {
int n1l = (int)n1->get_data().level;
int n2l = (int)n2->get_data().level;
- if (n1l == n2l && n1->get_is_gray() && !n2->get_is_gray())
+ if (n1l == n2l && n1->is_gray() && !n2->is_gray())
return true;
return (n1l < n2l);
});
@@ -1133,7 +1295,7 @@ bool NotificationManager::activate_existing(const NotificationManager::PopNotifi
NotificationType new_type = notification->get_type();
const std::string &new_text = notification->get_data().text1;
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end(); ++it) {
- if ((*it)->get_type() == new_type && !(*it)->get_finished()) {
+ if ((*it)->get_type() == new_type && !(*it)->is_finished()) {
if (new_type == NotificationType::CustomNotification || new_type == NotificationType::PlaterWarning) {
if (!(*it)->compare_text(new_text))
continue;
@@ -1166,6 +1328,78 @@ void NotificationManager::set_in_preview(bool preview)
}
}
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+void NotificationManager::update_notifications()
+{
+ static size_t last_size = 0;
+
+ for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
+ std::unique_ptr<PopNotification>& notification = *it;
+ if (notification->get_state() == PopNotification::EState::Finished)
+ it = m_pop_notifications.erase(it);
+ else {
+ notification->set_paused(m_hovered);
+ notification->update_state();
+ ++it;
+ }
+ }
+
+ m_requires_update = false;
+ for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
+ if (notification->requires_update()) {
+ m_requires_update = true;
+ break;
+ }
+ }
+
+ // update hovering state
+ m_hovered = false;
+ for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
+ if (notification->is_hovered()) {
+ m_hovered = true;
+ break;
+ }
+ }
+
+ size_t curr_size = m_pop_notifications.size();
+ m_requires_render = m_hovered || (last_size != curr_size);
+ last_size = curr_size;
+
+ if (!m_requires_render) {
+ for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
+ if (notification->requires_render()) {
+ m_requires_render = true;
+ break;
+ }
+ }
+ }
+
+ // actualizate timers
+ wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater());
+ while (p->GetParent() != nullptr)
+ p = p->GetParent();
+ wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
+ if (!top_level_wnd->IsActive())
+ return;
+
+ {
+ // Control the fade-out.
+ // time in seconds
+ long now = wxGetLocalTime();
+ // Pausing fade-out when the mouse is over some notification.
+ if (!m_hovered && m_last_time < now) {
+ if (now - m_last_time >= 1) {
+ for (auto& notification : m_pop_notifications) {
+ if (notification->get_state() != PopNotification::EState::Static)
+ notification->substract_remaining_time();
+ }
+ }
+ m_last_time = now;
+ }
+ }
+}
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+
bool NotificationManager::has_slicing_error_notification()
{
return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) {
diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp
index d8ca1e0bd..81c57eccb 100644
--- a/src/slic3r/GUI/NotificationManager.hpp
+++ b/src/slic3r/GUI/NotificationManager.hpp
@@ -140,7 +140,13 @@ public:
void set_in_preview(bool preview);
// Move to left to avoid colision with variable layer height gizmo.
void set_move_from_overlay(bool move) { m_move_from_overlay = move; }
-
+
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ void update_notifications();
+ bool requires_update() const { return m_requires_update; }
+ bool requires_render() const { return m_requires_render; }
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+
private:
// duration 0 means not disapearing
struct NotificationData {
@@ -175,6 +181,17 @@ private:
class PopNotification
{
public:
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ enum class EState
+ {
+ Unknown,
+ Static,
+ Countdown,
+ FadingOut,
+ ClosePending,
+ Finished
+ };
+#else
enum class RenderResult
{
Finished,
@@ -183,27 +200,41 @@ private:
Countdown,
Hovered
};
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler);
virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); }
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width);
+#else
RenderResult render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width);
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
// close will dissapear notification on next render
void close() { m_close_pending = true; }
// data from newer notification of same type
void update(const NotificationData& n);
- bool get_finished() const { return m_finished || m_close_pending; }
+ bool is_finished() const { return m_finished || m_close_pending; }
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ bool is_hovered() const { return m_hovered; }
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
// returns top after movement
float get_top() const { return m_top_y; }
//returns top in actual frame
float get_current_top() const { return m_top_y; }
const NotificationType get_type() const { return m_data.type; }
- const NotificationData get_data() const { return m_data; }
- const bool get_is_gray() const { return m_is_gray; }
+ const NotificationData get_data() const { return m_data; }
+ const bool is_gray() const { return m_is_gray; }
// Call equals one second down
void substract_remaining_time() { m_remaining_time--; }
void set_gray(bool g) { m_is_gray = g; }
void set_paused(bool p) { m_paused = p; }
bool compare_text(const std::string& text);
void hide(bool h) { m_hidden = h; }
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ void update_state();
+ bool requires_render() const { return m_fading_out || m_close_pending || m_finished; }
+ bool requires_update() const { return m_state != EState::Static; }
+ EState get_state() const { return m_state; }
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
protected:
// Call after every size change
@@ -218,9 +249,11 @@ private:
virtual void render_close_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
+#if !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void render_countdown(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
+#endif // !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
virtual void render_hypertext(ImGuiWrapper& imgui,
const float text_x, const float text_y,
const std::string text,
@@ -237,7 +270,10 @@ private:
// For reusing ImGUI windows.
NotificationIDProvider &m_id_provider;
- int m_id { 0 };
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ EState m_state { EState::Unknown };
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ int m_id { 0 };
bool m_initialized { false };
// Main text
std::string m_text1;
@@ -252,15 +288,22 @@ private:
bool m_paused { false };
int m_countdown_frame { 0 };
bool m_fading_out { false };
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ wxMilliClock_t m_fading_start { 0LL };
+#else
// total time left when fading beggins
- float m_fading_time { 0.0f };
- float m_current_fade_opacity { 1.f };
+ float m_fading_time{ 0.0f };
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ float m_current_fade_opacity { 1.0f };
// If hidden the notif is alive but not visible to user
bool m_hidden { false };
// m_finished = true - does not render, marked to delete
bool m_finished { false };
// Will go to m_finished next render
bool m_close_pending { false };
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ bool m_hovered { false };
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
// variables to count positions correctly
// all space without text
float m_window_width_offset;
@@ -390,6 +433,10 @@ private:
bool m_in_preview { false };
// True if the layer editing is enabled in Plater, so that the notifications are shifted left of it.
bool m_move_from_overlay { false };
+#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
+ bool m_requires_update{ false };
+ bool m_requires_render{ false };
+#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
//prepared (basic) notifications
const std::vector<NotificationData> basic_notifications = {