~aleteoryx/muditaos

585c612f5d880ed715c768bf8290dfb9f7e76f81 — marek303 5 years ago ae35521
[EGD-3315]Review changes: EventReminderWindow - localized date and time; unit tests for SelectFirstUpcoming query
M image/assets/lang/lang_de.json => image/assets/lang/lang_de.json +1 -0
@@ 41,6 41,7 @@
    "common_november": "November",
    "common_december": "December",
    "common_yesterday" : "Yesterday",
    "common_today" : "Today",
    "locale_12hour_min" : "%I:%M %p",
    "locale_24hour_min" : "%H:%M",
    "locale_date_full" : "%m/%d/%y",

M image/assets/lang/lang_en.json => image/assets/lang/lang_en.json +1 -0
@@ 53,6 53,7 @@
    "common_november": "November",
    "common_december": "December",
    "common_yesterday" : "Yesterday",
    "common_today" : "Today",
    "common_results_prefix": "Results: ",
    "common_search": "SEARCH",


M image/assets/lang/lang_fr.json => image/assets/lang/lang_fr.json +1 -0
@@ 41,6 41,7 @@
    "common_november": "November",
    "common_december": "December",
    "common_yesterday" : "Yesterday",
    "common_today" : "Today",
    "locale_12hour_min" : "%I:%M %p",
    "locale_24hour_min" : "%H:%M",
    "locale_date_full" : "%m/%d/%y",

M image/assets/lang/lang_pl.json => image/assets/lang/lang_pl.json +1 -0
@@ 41,6 41,7 @@
    "common_november": "listopada",
    "common_december": "grudnia",
    "common_yesterday" : "wczoraj",
    "common_today" : "dzisiaj",
    "locale_12hour_min" : "%I:%M",
    "locale_24hour_min" : "%H:%M",
    "locale_date_full" : "%d.%m.%y",

M image/assets/lang/lang_sp.json => image/assets/lang/lang_sp.json +1 -0
@@ 41,6 41,7 @@
    "common_november": "November",
    "common_december": "December",
    "common_yesterday" : "Yesterday",
    "common_today" : "Today",
    "locale_12hour_min" : "%I:%M %p",
    "locale_24hour_min" : "%H:%M",
    "locale_date_full" : "%m/%d/%y",

M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +3 -4
@@ 143,10 143,9 @@ namespace app
        windowsFactory.attach(custom_repeat_window, [](Application *app, const std::string &name) {
            return std::make_unique<gui::CustomRepeatWindow>(app, custom_repeat_window);
        });
        // mlucki
        windows.insert(std::pair<std::string, gui::AppWindow *>(
            style::window::calendar::name::event_reminder_window,
            new gui::EventReminderWindow(this, style::window::calendar::name::event_reminder_window)));
        windowsFactory.attach(event_reminder_window, [](Application *app, const std::string &name) {
            return std::make_unique<gui::EventReminderWindow>(app, event_reminder_window);
        });
    }

    void ApplicationCalendar::destroyUserInterface()

M module-apps/application-calendar/data/dateCommon.hpp => module-apps/application-calendar/data/dateCommon.hpp +2 -16
@@ 5,6 5,7 @@
#include <time/time_conversion.hpp>

using namespace std::chrono;
using namespace std::chrono_literals;

using Clock            = system_clock;
using TimePoint        = time_point<Clock>;


@@ 139,21 140,6 @@ inline TimePoint getFirstWeekDay(const TimePoint &tp)
    return finalDateTime;
}

inline std::string TimePointToDateString(const TimePoint &tp)
{
    return date::format("%F", time_point_cast<seconds>(tp));
}

inline std::string TimePointToTimeString(const TimePoint &tp)
{
    return date::format("%T", time_point_cast<seconds>(tp));
}

inline std::string TimePointToMinuteTimeString(const TimePoint &tp)
{
    return date::format("%H:%M", time_point_cast<seconds>(tp));
}

inline std::string TimePointToString(const TimePoint &tp, date::months months)
{
    date::year_month_day yearMonthDay     = date::year_month_day{date::floor<date::days>(tp)};


@@ 191,7 177,7 @@ inline std::string TimePointToLocalizedDateString(const TimePoint &tp, const std
    return timestamp.str(format);
}

inline std::string TimePointToLocalizedTimeString(const TimePoint &tp, const std::string format)
inline std::string TimePointToLocalizedTimeString(const TimePoint &tp, const std::string format = "")
{
    auto time = TimePointToTimeT(tp);
    utils::time::Time timestamp(time);

M module-apps/application-calendar/widgets/CalendarStyle.hpp => module-apps/application-calendar/widgets/CalendarStyle.hpp +12 -0
@@ 8,6 8,18 @@ namespace style
    {
        namespace calendar
        {
            namespace imageCircleTop
            {
                constexpr uint32_t x = 116;
                constexpr uint32_t y = 59;
                constexpr auto name  = "circle_top";
            } // namespace imageCircleTop
            namespace imageCircleBottom
            {
                constexpr uint32_t x = 106;
                constexpr uint32_t y = 240;
                constexpr auto name  = "circle_bottom";
            } // namespace imageCircleBottom

            namespace name
            {

M module-apps/application-calendar/windows/EventReminderWindow.cpp => module-apps/application-calendar/windows/EventReminderWindow.cpp +32 -16
@@ 45,30 45,46 @@ namespace gui

        bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::ok));
        bottomBar->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);

        topImage = new gui::Image(this, 116, 59, 0, 0, "circle_top");
        topImage->setAlignment(Alignment(gui::Alignment::Horizontal::Center));
        bottomImage = new gui::Image(this, 106, 240, 0, 0, "circle_bottom");
        bottomImage->setAlignment(Alignment(gui::Alignment::Horizontal::Center));

        dateLabel = new Label(this, 0, 120, 480, 80);
        bottomBar->setBorderColor(ColorNoColor);

        const uint32_t w = this->getWidth() - style::window::default_left_margin - style::window::default_right_margin;
        const uint32_t h = this->getHeight() - bottomBar->getHeight();
        body             = new gui::VBox(this, style::window::default_left_margin, topBar->getHeight(), w, h);
        body->setBorderColor(gui::ColorNoColor);

        topImage = new gui::Image(body,
                                  style::window::calendar::imageCircleTop::x,
                                  style::window::calendar::imageCircleTop::y,
                                  0,
                                  0,
                                  style::window::calendar::imageCircleTop::name);
        topImage->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center));

        dateLabel = new Label(body, 0, 0, w, style::window::label::default_h);
        dateLabel->setFont(style::window::font::smallbold);
        dateLabel->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        dateLabel->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        dateLabel->setBorderColor(ColorNoColor);

        timeLabel = new Label(this, 0, 170, 480, 80);
        timeLabel = new Label(body, 0, 0, w, style::window::label::default_h);
        timeLabel->setFont(style::window::font::largelight);
        timeLabel->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        timeLabel->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        timeLabel->setBorderColor(ColorNoColor);

        bottomImage = new gui::Image(body,
                                     style::window::calendar::imageCircleBottom::x,
                                     style::window::calendar::imageCircleBottom::y,
                                     0,
                                     0,
                                     style::window::calendar::imageCircleBottom::name);
        bottomImage->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center));

        descriptionLabel = new Label(this, 0, 350, 480, 80);
        descriptionLabel = new Label(body, 0, 0, w, 2 * style::window::label::default_h);
        descriptionLabel->setFont(style::window::font::big);
        descriptionLabel->setAlignment(
            gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        descriptionLabel->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        descriptionLabel->setBorderColor(ColorNoColor);

        setFocusItem(nullptr);
        setFocusItem(body);
    }

    void EventReminderWindow::destroyInterface()


@@ 100,8 116,8 @@ namespace gui
        }

        eventRecord    = item->getData();
        dateLabel->setText(TimePointToDateString(eventRecord->date_from));
        timeLabel->setText(TimePointToMinuteTimeString(eventRecord->date_from));
        dateLabel->setText(TimePointToLocalizedDateString(eventRecord->date_from));
        timeLabel->setText(TimePointToLocalizedTimeString(eventRecord->date_from));
        descriptionLabel->setText(eventRecord->title);

        startTimer();

M module-apps/application-calendar/windows/EventReminderWindow.hpp => module-apps/application-calendar/windows/EventReminderWindow.hpp +2 -1
@@ 16,8 16,9 @@ namespace gui
        std::unique_ptr<sys::Timer> reminderTimer;

      protected:
        std::shared_ptr<EventsRecord> eventRecord = nullptr;
        std::shared_ptr<EventsRecord> eventRecord;

        gui::VBox *body         = nullptr;
        Label *dateLabel        = nullptr;
        Label *timeLabel        = nullptr;
        Label *descriptionLabel = nullptr;

M module-db/tests/EventsRecord_tests.cpp => module-db/tests/EventsRecord_tests.cpp +87 -34
@@ 10,6 10,7 @@
#include "module-db/queries/calendar/QueryEventsAdd.hpp"
#include "module-db/queries/calendar/QueryEventsRemove.hpp"
#include "module-db/queries/calendar/QueryEventsEdit.hpp"
#include "module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp"

#include <vfs.hpp>



@@ 41,14 42,14 @@ TEST_CASE("Events Record tests")
    {
        EventsTableRow tableRow{{.ID = 10},
                                "Event3",
                                TimePointFromString("2019-10-20 14:24"),
                                TimePointFromString("2019-10-20 15:36"),
                                TimePointFromString("2019-10-20 14:24:00"),
                                TimePointFromString("2019-10-20 15:36:00"),
                                1,
                                2};
        EventsRecord testRec(tableRow);
        REQUIRE(testRec.title == "Event3");
        REQUIRE(testRec.date_from == TimePointFromString("2019-10-20 14:24"));
        REQUIRE(testRec.date_till == TimePointFromString("2019-10-20 15:36"));
        REQUIRE(testRec.date_from == TimePointFromString("2019-10-20 14:24:00"));
        REQUIRE(testRec.date_till == TimePointFromString("2019-10-20 15:36:00"));
        REQUIRE(testRec.reminder == 1);
        REQUIRE(testRec.repeat == 2);
        REQUIRE(testRec.isValid());


@@ 60,12 61,16 @@ TEST_CASE("Events Record tests")
    auto numberOfEvents = eventsRecordInterface.GetCount();
    REQUIRE(numberOfEvents == 0);

    EventsTableRow tableRow{
        {.ID = 10}, "Event1", TimePointFromString("2019-10-20 14:24"), TimePointFromString("2019-10-20 15:36"), 1, 2};
    EventsTableRow tableRow{{.ID = 10},
                            "Event1",
                            TimePointFromString("2019-10-20 14:24:00"),
                            TimePointFromString("2019-10-20 15:36:00"),
                            1,
                            2};
    auto rec = EventsRecord(tableRow);
    REQUIRE(rec.title == "Event1");
    REQUIRE(rec.date_from == TimePointFromString("2019-10-20 14:24"));
    REQUIRE(rec.date_till == TimePointFromString("2019-10-20 15:36"));
    REQUIRE(rec.date_from == TimePointFromString("2019-10-20 14:24:00"));
    REQUIRE(rec.date_till == TimePointFromString("2019-10-20 15:36:00"));
    REQUIRE(rec.reminder == 1);
    REQUIRE(rec.repeat == 2);
    REQUIRE(rec.isValid());


@@ 80,8 85,8 @@ TEST_CASE("Events Record tests")
        auto entry = eventsRecordInterface.GetByID(1);
        REQUIRE(entry.ID == 1);
        REQUIRE(entry.title == "Event1");
        REQUIRE(entry.date_from == TimePointFromString("2019-10-20 14:24"));
        REQUIRE(entry.date_till == TimePointFromString("2019-10-20 15:36"));
        REQUIRE(entry.date_from == TimePointFromString("2019-10-20 14:24:00"));
        REQUIRE(entry.date_till == TimePointFromString("2019-10-20 15:36:00"));
        REQUIRE(entry.reminder == 1);
        REQUIRE(entry.repeat == 2);
        REQUIRE(entry.isValid());


@@ 99,12 104,16 @@ TEST_CASE("Events Record tests")
        REQUIRE_FALSE(entry.isValid());
    }

    EventsTableRow tableRow2{
        {.ID = 10}, "Event2", TimePointFromString("2025-10-20 14:24"), TimePointFromString("2025-10-20 15:36"), 1, 2};
    EventsTableRow tableRow2{{.ID = 10},
                             "Event2",
                             TimePointFromString("2025-10-20 14:24:00"),
                             TimePointFromString("2025-10-20 15:36:00"),
                             1,
                             2};
    auto rec2 = EventsRecord(tableRow2);
    REQUIRE(rec2.title == "Event2");
    REQUIRE(rec2.date_from == TimePointFromString("2025-10-20 14:24"));
    REQUIRE(rec2.date_till == TimePointFromString("2025-10-20 15:36"));
    REQUIRE(rec2.date_from == TimePointFromString("2025-10-20 14:24:00"));
    REQUIRE(rec2.date_till == TimePointFromString("2025-10-20 15:36:00"));
    REQUIRE(rec2.reminder == 1);
    REQUIRE(rec2.repeat == 2);
    REQUIRE(rec2.isValid());


@@ 143,8 152,8 @@ TEST_CASE("Events Record tests")

        SECTION("Get table rows by SELECT invalid")
        {
            auto retOffsetLimit = eventsRecordInterface.Select(TimePointFromString("2010-10-20 14:24"),
                                                               TimePointFromString("2010-10-20 15:36"));
            auto retOffsetLimit = eventsRecordInterface.Select(TimePointFromString("2010-10-20 14:24:00"),
                                                               TimePointFromString("2010-10-20 15:36:00"));
            REQUIRE(retOffsetLimit->size() == 0);
        }
    }


@@ 153,8 162,8 @@ TEST_CASE("Events Record tests")
    {
        auto entryPre      = eventsRecordInterface.GetByID(1);
        entryPre.title     = "newTitle";
        entryPre.date_from = TimePointFromString("2019-12-31 23:59");
        entryPre.date_till = TimePointFromString("2019-12-31 23:59");
        entryPre.date_from = TimePointFromString("2019-12-31 23:59:00");
        entryPre.date_till = TimePointFromString("2019-12-31 23:59:00");
        REQUIRE(eventsRecordInterface.Update(entryPre));

        auto entry = eventsRecordInterface.GetByID(1);


@@ 166,12 175,31 @@ TEST_CASE("Events Record tests")
        REQUIRE(entry.repeat == entryPre.repeat);
    }

    EventsTableRow tableRow3{
        {.ID = 3}, "Event3", TimePointFromString("2021-10-20 14:24"), TimePointFromString("2021-10-20 15:36"), 1, 2};
    REQUIRE(numberOfEvents == 8);

    SECTION("Select first upcoming event")
    {
        TimePoint start_date = TimePointFromString("2025-10-27 14:24:00");
        auto nextUpcoming    = eventsRecordInterface.SelectFirstUpcoming(start_date, start_date);
        REQUIRE(nextUpcoming->size() == 1);
        EventsRecord nextEventsRecord = nextUpcoming->at(0);
        REQUIRE(nextEventsRecord.ID == 7);

        start_date   = TimePointFromString("2025-11-10 14:24:00");
        nextUpcoming = eventsRecordInterface.SelectFirstUpcoming(start_date, start_date);
        REQUIRE(nextUpcoming->size() == 0);
    }

    EventsTableRow tableRow3{{.ID = 3},
                             "Event3",
                             TimePointFromString("2021-10-20 14:24:00"),
                             TimePointFromString("2021-10-20 15:36:00"),
                             1,
                             2};
    auto rec3 = EventsRecord(tableRow3);
    REQUIRE(rec3.title == "Event3");
    REQUIRE(rec3.date_from == TimePointFromString("2018-10-20 14:24"));
    REQUIRE(rec3.date_till == TimePointFromString("2021-10-20 15:36"));
    REQUIRE(rec3.date_from == TimePointFromString("2021-10-20 14:24:00"));
    REQUIRE(rec3.date_till == TimePointFromString("2021-10-20 15:36:00"));
    REQUIRE(rec3.reminder == 1);
    REQUIRE(rec3.repeat == 2);
    REQUIRE(rec3.isValid());


@@ 257,25 285,34 @@ TEST_CASE("Events Record tests")
        REQUIRE(recordGet.repeat == repeat);
    };

    auto selectFirstUpcomingEvent = [&](TimePoint filter_from, TimePoint filter_till) {
        auto query  = std::make_shared<db::query::events::SelectFirstUpcoming>(filter_from, filter_till);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::SelectFirstUpcomingResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto records = result->getResult();
        return records;
    };

    SECTION("Get via query")
    {
        getQuery(3, "Event1", TimePointFromString("2021-10-20 14:24"), TimePointFromString("2021-10-20 15:36"));
        getQuery(3, "Event1", TimePointFromString("2021-10-20 14:24:00"), TimePointFromString("2021-10-20 15:36:00"));
    }

    SECTION("GetFiltered via query")
    {
        getFiltered(1,
                    "Event1",
                    TimePointFromString("2019-10-20 14:24"),
                    TimePointFromString("2019-10-20 15:36"),
                    TimePointFromString("2018-10-20 14:24"),
                    TimePointFromString("2019-10-20 15:36"));
                    TimePointFromString("2019-10-20 14:24:00"),
                    TimePointFromString("2019-10-20 15:36:00"),
                    TimePointFromString("2018-10-20 14:24:00"),
                    TimePointFromString("2019-10-20 15:36:00"));
    }

    SECTION("Add via query")
    {
        AddQuery(3, "Event3", TimePointFromString("2026-10-20 14:24"), TimePointFromString("2022-10-20 15:36"));
        getQuery(4, "Event1", TimePointFromString("2026-10-20 14:24"), TimePointFromString("2022-10-20 15:36"));
        AddQuery(3, "Event3", TimePointFromString("2026-10-20 14:24:00"), TimePointFromString("2022-10-20 15:36:00"));
        getQuery(4, "Event1", TimePointFromString("2026-10-20 14:24:00"), TimePointFromString("2022-10-20 15:36:00"));
    }

    SECTION("Remove via query")


@@ 291,7 328,8 @@ TEST_CASE("Events Record tests")

    SECTION("Update via query")
    {
        EditQuery(2, "Event1", TimePointFromString("2021-10-20 14:24"), TimePointFromString("2021-10-20 15:36"), 1, 2);
        EditQuery(
            2, "Event1", TimePointFromString("2021-10-20 14:24:00"), TimePointFromString("2021-10-20 15:36:00"), 1, 2);
    }

    SECTION("Get All via query")


@@ 306,10 344,10 @@ TEST_CASE("Events Record tests")

    SECTION("Get All Limited via query")
    {
        AddQuery(3, "Event1", TimePointFromString("2026-10-20 14:24"), TimePointFromString("2022-10-20 15:36"));
        AddQuery(3, "Event2", TimePointFromString("2020-10-20 14:24"), TimePointFromString("2022-10-20 15:36"));
        AddQuery(3, "Event3", TimePointFromString("2025-10-20 14:24"), TimePointFromString("2022-10-20 15:36"));
        AddQuery(3, "Event4", TimePointFromString("2019-10-20 14:24"), TimePointFromString("2022-10-20 15:36"));
        AddQuery(3, "Event1", TimePointFromString("2026-10-20 14:24:00"), TimePointFromString("2022-10-20 15:36:00"));
        AddQuery(3, "Event2", TimePointFromString("2020-10-20 14:24:00"), TimePointFromString("2022-10-20 15:36:00"));
        AddQuery(3, "Event3", TimePointFromString("2025-10-20 14:24:00"), TimePointFromString("2022-10-20 15:36:00"));
        AddQuery(3, "Event4", TimePointFromString("2019-10-20 14:24:00"), TimePointFromString("2022-10-20 15:36:00"));
        auto count1     = getAllLimited(0, 2);
        auto count2     = getAllLimited(2, 5);
        auto &eventsTbl = eventsDb.events;


@@ 318,5 356,20 @@ TEST_CASE("Events Record tests")
        REQUIRE(*count2 == count3);
    }

    SECTION("Select first upcoming via query")
    {
        auto date_from = TimePointFromString("2025-10-27 14:24:00");
        auto date_till = TimePointFromString("2026-10-20 14:24:00");
        auto records   = selectFirstUpcomingEvent(date_from, date_till);
        REQUIRE(records->size() == 1);
        auto firstEvent = records->at(0);
        REQUIRE(firstEvent.ID == 7);

        date_from = TimePointFromString("2025-11-10 14:24:00");
        date_till = TimePointFromString("2026-10-20 14:24:00");
        records   = selectFirstUpcomingEvent(date_from, date_till);
        REQUIRE(records->size() == 0);
    }

    Database::deinitialize();
}

M module-db/tests/EventsTable_tests.cpp => module-db/tests/EventsTable_tests.cpp +111 -26
@@ 32,19 32,20 @@ TEST_CASE("Events Table tests")
        REQUIRE(testRow.date_till == TIME_POINT_INVALID);
        REQUIRE(testRow.reminder == 0);
        REQUIRE(testRow.repeat == 0);
        REQUIRE(testRow.reminder_fired == TIME_POINT_INVALID);
        REQUIRE_FALSE(testRow.isValid());
    }

    REQUIRE(eventsTbl.add({{.ID = 0},
                           .title     = "Event3",
                           .date_from = TimePointFromString("2019-10-20 14:24"),
                           .date_till = TimePointFromString("2019-10-20 15:36"),
                           .date_from = TimePointFromString("2019-10-20 14:24:00"),
                           .date_till = TimePointFromString("2019-10-20 15:36:00"),
                           .reminder  = 1,
                           .repeat    = 2}));
    REQUIRE(eventsTbl.add({{.ID = 0},
                           .title     = "Event4",
                           .date_from = TimePointFromString("2021-10-20 12:24"),
                           .date_till = TimePointFromString("2021-10-20 15:36"),
                           .date_from = TimePointFromString("2021-10-20 12:24:00"),
                           .date_till = TimePointFromString("2021-10-20 15:36:00"),
                           .reminder  = 0,
                           .repeat    = 3}));



@@ 55,8 56,8 @@ TEST_CASE("Events Table tests")
        auto entry = eventsTbl.getById(2);
        REQUIRE(entry.ID == 2);
        REQUIRE(entry.title == "Event4");
        REQUIRE(entry.date_from == TimePointFromString("2021-10-20 12:24"));
        REQUIRE(entry.date_till == TimePointFromString("2021-10-20 15:36"));
        REQUIRE(entry.date_from == TimePointFromString("2021-10-20 12:24:00"));
        REQUIRE(entry.date_till == TimePointFromString("2021-10-20 15:36:00"));
        REQUIRE(entry.reminder == 0);
        REQUIRE(entry.repeat == 3);
        REQUIRE(entry.isValid());


@@ 71,8 72,8 @@ TEST_CASE("Events Table tests")
        auto entry = eventsTbl.getById(1);
        REQUIRE(entry.ID == 1);
        REQUIRE(entry.title == "Event3");
        REQUIRE(entry.date_from == TimePointFromString("2019-10-20 14:24"));
        REQUIRE(entry.date_till == TimePointFromString("2019-10-20 15:36"));
        REQUIRE(entry.date_from == TimePointFromString("2019-10-20 14:24:00"));
        REQUIRE(entry.date_till == TimePointFromString("2019-10-20 15:36:00"));
        REQUIRE(entry.reminder == 1);
        REQUIRE(entry.repeat == 2);
        REQUIRE(entry.isValid());


@@ 82,16 83,16 @@ TEST_CASE("Events Table tests")
    {
        auto entry = EventsTableRow({{.ID = 2},
                                     "TestUpdateEvent",
                                     TimePointFromString("2019-10-20 15:00"),
                                     TimePointFromString("2019-10-20 18:54"),
                                     TimePointFromString("2019-10-20 15:00:00"),
                                     TimePointFromString("2019-10-20 18:54:00"),
                                     0,
                                     2});
        REQUIRE(eventsTbl.update(entry));
        auto record = eventsTbl.getById(2);
        REQUIRE(record.ID == 2);
        REQUIRE(record.title == "TestUpdateEvent");
        REQUIRE(record.date_from == TimePointFromString("2019-10-20 15:00"));
        REQUIRE(record.date_till == TimePointFromString("2019-10-20 18:54"));
        REQUIRE(record.date_from == TimePointFromString("2019-10-20 15:00:00"));
        REQUIRE(record.date_till == TimePointFromString("2019-10-20 18:54:00"));
        REQUIRE(record.reminder == 0);
        REQUIRE(record.repeat == 2);
        REQUIRE(record.isValid());


@@ 101,43 102,43 @@ TEST_CASE("Events Table tests")
    {
        REQUIRE(eventsTbl.add({{.ID = 0},
                               .title     = "Event5",
                               .date_from = TimePointFromString("2019-10-20 14:24"),
                               .date_till = TimePointFromString("2019-10-20 15:36"),
                               .date_from = TimePointFromString("2019-10-20 14:24:00"),
                               .date_till = TimePointFromString("2019-10-20 15:36:00"),
                               .reminder  = 1,
                               .repeat    = 2}));
        REQUIRE(eventsTbl.add({{.ID = 1},
                               .title     = "Event6",
                               .date_from = TimePointFromString("2021-04-19 12:24"),
                               .date_till = TimePointFromString("2021-04-20 15:36"),
                               .date_from = TimePointFromString("2021-04-19 12:24:00"),
                               .date_till = TimePointFromString("2021-04-20 15:36:00"),
                               .reminder  = 0,
                               .repeat    = 3}));
        REQUIRE(eventsTbl.add({{.ID = 2},
                               .title     = "Event7",
                               .date_from = TimePointFromString("2019-10-20 15:24"),
                               .date_till = TimePointFromString("2019-10-20 15:36"),
                               .date_from = TimePointFromString("2019-10-20 15:24:00"),
                               .date_till = TimePointFromString("2019-10-20 15:36:00"),
                               .reminder  = 1,
                               .repeat    = 2}));
        REQUIRE(eventsTbl.add({{.ID = 3},
                               .title     = "Event8",
                               .date_from = TimePointFromString("2021-04-19 12:24"),
                               .date_till = TimePointFromString("2019-10-20 15:36"),
                               .date_from = TimePointFromString("2021-04-19 12:24:00"),
                               .date_till = TimePointFromString("2019-10-20 15:36:00"),
                               .reminder  = 0,
                               .repeat    = 3}));
        REQUIRE(eventsTbl.add({{.ID = 4},
                               .title     = "Event9",
                               .date_from = TimePointFromString("2025-10-20 15:24"),
                               .date_till = TimePointFromString("2025-10-20 15:36"),
                               .date_from = TimePointFromString("2025-10-20 15:24:00"),
                               .date_till = TimePointFromString("2025-10-20 15:36:00"),
                               .reminder  = 1,
                               .repeat    = 2}));
        REQUIRE(eventsTbl.add({{.ID = 5},
                               .title     = "Event10",
                               .date_from = TimePointFromString("2021-12-19 12:24"),
                               .date_till = TimePointFromString("2021-12-20 15:36"),
                               .date_from = TimePointFromString("2021-12-19 12:24:00"),
                               .date_till = TimePointFromString("2021-12-20 15:36:00"),
                               .reminder  = 0,
                               .repeat    = 3}));

        auto entries = eventsTbl.selectByDatePeriod(TimePointFromString("2000-01-01 00:00"),
                                                    TimePointFromString("2012-12-31 23:59"));
        auto entries = eventsTbl.selectByDatePeriod(TimePointFromString("2000-01-01 00:00:00"),
                                                    TimePointFromString("2012-12-31 23:59:00"));

        REQUIRE(entries.size() == 0);
    }


@@ 146,6 147,7 @@ TEST_CASE("Events Table tests")
        REQUIRE(response);
    }
    REQUIRE(eventsTbl.count() == 0);

    SECTION("Get all limited by date")
    {
        for (uint32_t i = 1; i <= 3; ++i) {


@@ 213,5 215,88 @@ TEST_CASE("Events Table tests")
            ++index;
        }
    }

    SECTION("Select first upcoming event")
    {
        for (uint32_t i = 1; i <= 10; ++i) {
            auto response = eventsTbl.removeById(i);
            REQUIRE(response);
        }
        REQUIRE(eventsTbl.count() == 0);

        const std::array<TimePoint, 6> paramDate{TimePointFromString("2018-10-20 15:24:00"),
                                                 TimePointFromString("2019-10-30 14:24:00"),
                                                 TimePointFromString("2020-10-20 14:24:00"),
                                                 TimePointFromString("2021-12-20 14:24:00"),
                                                 TimePointFromString("2022-10-20 14:24:00"),
                                                 TimePointFromString("2023-10-20 14:24:00")};
        TimePoint startDate1 = TimePointFromString("2018-10-20 14:24:00");
        TimePoint startDate2 = TimePointFromString("2020-10-20 14:24:00");

        TimePoint tillDate  = TimePointFromString("2030-10-20 15:24:00");
        TimePoint firedDate = TimePointFromString("2018-10-20 14:24:00");

        REQUIRE(eventsTbl.add({{.ID = 1},
                               .title          = "Event1",
                               .date_from      = paramDate[0],
                               .date_till      = tillDate,
                               .reminder       = 120,
                               .repeat         = 0,
                               .reminder_fired = TIME_POINT_INVALID}));
        REQUIRE(eventsTbl.add({{.ID = 2},
                               .title          = "Event2",
                               .date_from      = paramDate[1],
                               .date_till      = tillDate,
                               .reminder       = 120,
                               .repeat         = 0,
                               .reminder_fired = TIME_POINT_INVALID}));
        REQUIRE(eventsTbl.add({{.ID = 3},
                               .title          = "Event3",
                               .date_from      = paramDate[2],
                               .date_till      = tillDate,
                               .reminder       = 120,
                               .repeat         = 0,
                               .reminder_fired = firedDate}));
        REQUIRE(eventsTbl.add({{.ID = 4},
                               .title          = "Event4",
                               .date_from      = paramDate[3],
                               .date_till      = tillDate,
                               .reminder       = 120,
                               .repeat         = 0,
                               .reminder_fired = firedDate}));
        REQUIRE(eventsTbl.add({{.ID = 5},
                               .title          = "Event5",
                               .date_from      = paramDate[4],
                               .date_till      = tillDate,
                               .reminder       = 120,
                               .repeat         = 0,
                               .reminder_fired = TIME_POINT_INVALID}));
        REQUIRE(eventsTbl.add({{.ID = 6},
                               .title          = "Event6",
                               .date_from      = paramDate[5],
                               .date_till      = tillDate,
                               .reminder       = 120,
                               .repeat         = 0,
                               .reminder_fired = TIME_POINT_INVALID}));

        auto entries = eventsTbl.SelectFirstUpcoming(startDate1, tillDate);
        REQUIRE(entries.size() == 1);
        for (auto entry : entries) {
            REQUIRE(entry.title == "Event2");
        }

        entries = eventsTbl.SelectFirstUpcoming(startDate2, tillDate);
        REQUIRE(entries.size() == 1);
        for (auto entry : entries) {
            REQUIRE(entry.title == "Event5");
        }

        for (uint32_t i = 1; i <= 10; ++i) {
            auto response = eventsTbl.removeById(i);
            REQUIRE(response);
        }
        REQUIRE(eventsTbl.count() == 0);
    }

    Database::deinitialize();
}

M module-gui/gui/widgets/Style.hpp => module-gui/gui/widgets/Style.hpp +1 -0
@@ 164,6 164,7 @@ namespace style
            const inline std::string November  = "common_november";
            const inline std::string December  = "common_december";
            const inline std::string Yesterday = "common_yesterday";
            const inline std::string Today     = "common_today";
        } // namespace common
    }     // namespace strings


M module-services/service-time/ServiceTime.cpp => module-services/service-time/ServiceTime.cpp +1 -3
@@ 46,9 46,7 @@ namespace stm
                responseMsg = std::make_shared<TimeResponseMessage>(false);
                break;
            }
            if (msg->interface == db::Interface::Name::Events &&
                (msg->type == db::Query::Type::Create || msg->type == db::Query::Type::Update ||
                 msg->type == db::Query::Type::Delete)) {
            if (msg->interface == db::Interface::Name::Events && msg->dataModified()) {

                calendarEvents.processNextEvent();


M module-services/service-time/ServiceTime.hpp => module-services/service-time/ServiceTime.hpp +1 -5
@@ 1,6 1,4 @@
#ifndef PUREPHONE_SERVICETIME_HPP
#define PUREPHONE_SERVICETIME_HPP

#pragma once
#include "Service/Service.hpp"
#include "ServiceTime.hpp"
#include <functional>


@@ 35,5 33,3 @@ namespace stm
    };

} /* namespace stm */

#endif // PUREPHONE_SERVICETIME_HPP

M module-services/service-time/messages/TimeMessage.hpp => module-services/service-time/messages/TimeMessage.hpp +3 -19
@@ 1,28 1,14 @@
/*
 *  @file TimeMessage.hpp
 *  @author
 *  @date 08.05.20
 *  @brief
 *  @copyright Copyright (C) 2019 mudita.com
 *  @details
 */
#pragma once

#ifndef PUREPHONE_TIMEMESSAGE_HPP
#define PUREPHONE_TIMEMESSAGE_HPP

#include <memory>
#include <variant>
#include "Service/Message.hpp"
#include "MessageType.hpp"

class TimeMessage : public sys::DataMessage
{
  public:
    TimeMessage(MessageType messageType) : sys::DataMessage(messageType), type(messageType){};
    explicit TimeMessage(MessageType messageType) : sys::DataMessage(messageType){};

    virtual ~TimeMessage() = default;

    MessageType type = MessageType::MessageTypeUninitialized;
};

class TimersProcessingStartMessage : public TimeMessage


@@ 55,10 41,8 @@ class TimeResponseMessage : public sys::ResponseMessage
        : sys::ResponseMessage(sys::ReturnCodes::Success, responseTo), retCode(retCode), data(retdata){};
    TimeResponseMessage(bool retCode, MessageType responseTo)
        : sys::ResponseMessage(sys::ReturnCodes::Success, responseTo), retCode(retCode){};
    virtual ~TimeResponseMessage(){};
    virtual ~TimeResponseMessage() = default;

    bool retCode;
    std::string data;
};

#endif // PUREPHONE_SERVICETIME_HPP

M module-services/service-time/timeEvents/CalendarTimeEvents.cpp => module-services/service-time/timeEvents/CalendarTimeEvents.cpp +1 -1
@@ 12,7 12,7 @@

namespace stm
{
    constexpr static const int eventTimerMinSkipInterval = 100;
    constexpr static auto eventTimerMinSkipInterval = 100ms;

    CalendarTimeEvents::CalendarTimeEvents(sys::Service *service) : TimeEvents(service)
    {}

M module-services/service-time/timeEvents/CalendarTimeEvents.hpp => module-services/service-time/timeEvents/CalendarTimeEvents.hpp +1 -1
@@ 23,7 23,7 @@ namespace stm

      public:
        CalendarTimeEvents() = delete;
        CalendarTimeEvents(sys::Service *service);
        explicit CalendarTimeEvents(sys::Service *service);
        ~CalendarTimeEvents() = default;
    };


M module-services/service-time/timeEvents/TimeEvents.hpp => module-services/service-time/timeEvents/TimeEvents.hpp +1 -1
@@ 30,7 30,7 @@ namespace stm

      public:
        TimeEvents() = delete;
        TimeEvents(sys::Service *service);
        explicit TimeEvents(sys::Service *service);
        ~TimeEvents();

        /// startProcessing - starts processing of events