~aleteoryx/muditaos

b16523e32502757ec6ae11ff7716f639de921a54 — Michał Kamoń 4 years ago db4b41c
[EGD-6222] Fix the App Calendar memory leaks

This PR fixes:
 -several explicit uses of `new` that were not matched by `delete`
 -dangling `CalendarTimeItem`s
 -reset of focus on the `allDayEventCheckBox` check/uncheck
 -exiting the app form `allEventsWindow` on `KEY_RF`
M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +2 -3
@@ 167,14 167,13 @@ namespace app
            "",
            [=]() -> bool {
                LOG_DEBUG("Switch to new event window");
                std::unique_ptr<EventRecordData> eventData = std::make_unique<EventRecordData>();
                eventData->setDescription(style::window::calendar::new_event);
                auto event       = std::make_shared<EventsRecord>();
                event->date_from = dateFilter;
                event->date_till = dateFilter + std::chrono::hours(utils::time::Locale::max_hour_24H_mode) +
                                   std::chrono::minutes(utils::time::Locale::max_minutes);
                eventData->setData(event);

                auto eventData = std::make_unique<EventRecordData>(std::move(event));
                eventData->setDescription(style::window::calendar::new_event);
                switchWindow(
                    style::window::calendar::name::new_edit_event, gui::ShowMode::GUI_SHOW_INIT, std::move(eventData));
                return true;

M module-apps/application-calendar/data/CalendarData.hpp => module-apps/application-calendar/data/CalendarData.hpp +2 -8
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 18,17 18,11 @@ class EventRecordData : public gui::SwitchData
    std::shared_ptr<EventsRecord> record;

  public:
    EventRecordData() = default;
    EventRecordData(std::shared_ptr<EventsRecord> record) : record{std::move(record)} {};
    virtual ~EventRecordData() = default;
    explicit EventRecordData(std::shared_ptr<EventsRecord> record) : record{std::move(record)} {};
    std::shared_ptr<EventsRecord> getData()
    {
        return record;
    };
    virtual void setData(std::shared_ptr<EventsRecord> rec)
    {
        record = std::move(rec);
    };
};

class WeekDaysRepeatData : public gui::SwitchData

M module-apps/application-calendar/data/dateCommon.hpp => module-apps/application-calendar/data/dateCommon.hpp +2 -2
@@ 246,8 246,8 @@ inline TimePoint TimePointFromYearMonthDay(const calendar::YearMonthDay &ymd)
inline time_t TimePointToMin(const TimePoint &tp)
{
    auto time     = TimePointToTimeT(tp);
    auto duration = new utils::time::Duration(time);
    auto minutes  = duration->getMinutes();
    auto duration = utils::time::Duration(time);
    auto minutes  = duration.getMinutes();
    return minutes;
}


M module-apps/application-calendar/models/DayEventsModel.cpp => module-apps/application-calendar/models/DayEventsModel.cpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DayEventsModel.hpp"


@@ 70,7 70,6 @@ auto DayEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
            return false;
        }

        auto records = response->getResult();
        if (auto app = dynamic_cast<app::ApplicationCalendar *>(application); app != nullptr) {
            if (response->getCountResult() == 0) {
                LOG_DEBUG("Empty records");


@@ 80,6 79,7 @@ auto DayEventsModel::handleQueryResponse(db::QueryResult *queryResult) -> bool
                }
            }
            auto eventShift = app->getEventShift();
            auto records    = response->getResult();
            if (eventShift) {
                for (auto &record : records) {
                    record.date_from += std::chrono::hours(eventShift);

M module-apps/application-calendar/models/NewEditEventModel.cpp => module-apps/application-calendar/models/NewEditEventModel.cpp +74 -97
@@ 3,17 3,21 @@

#include "NewEditEventModel.hpp"
#include "application-calendar/widgets/NewEventCheckBoxWithLabel.hpp"
#include "application-calendar/widgets/TextWithLabelItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include <application-calendar/widgets/CalendarDateItem.hpp>
#include <application-calendar/widgets/CalendarTimeItem.hpp>
#include <application-calendar/widgets/SeveralOptionsItem.hpp>
#include "application-calendar/data/CalendarData.hpp"
#include "application-calendar/ApplicationCalendar.hpp"
#include "AppWindow.hpp"
#include <BottomBar.hpp>
#include <ListView.hpp>
#include <module-db/queries/calendar/QueryEventsAdd.hpp>
#include <module-db/queries/calendar/QueryEventsEdit.hpp>
#include <service-db/DBServiceAPI.hpp>
#include <time/time_conversion.hpp>

NewEditEventModel::NewEditEventModel(app::Application *app, bool mode24H) : application(app), mode24H(mode24H)
NewEditEventModel::NewEditEventModel(app::Application *app) : application(app)
{}

unsigned int NewEditEventModel::requestRecordsCount()


@@ 32,27 36,6 @@ void NewEditEventModel::requestRecords(const uint32_t offset, const uint32_t lim
    list->onProviderDataUpdate();
}

uint32_t NewEditEventModel::getRepeatOptionValue()
{
    if (repeat != nullptr) {
        return repeat->repeatOptionValue;
    }
    else {
        LOG_ERROR("Repeat option value returned before assigned!");
        return 0;
    }
}

void NewEditEventModel::setRepeatOptionValue(const uint32_t &value)
{
    if (repeat != nullptr) {
        repeat->repeatOptionValue = value;
    }
    else {
        LOG_ERROR("Value not assigned. Repeat option item was not ready!");
    }
}

gui::ListItem *NewEditEventModel::getItem(gui::Order order)
{
    return getRecord(order);


@@ 70,22 53,14 @@ void NewEditEventModel::createData(bool allDayEvent)
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); });

    allDayEventCheckBox = new gui::NewEventCheckBoxWithLabel(
        application, utils::localize.get("app_calendar_new_edit_event_allday"), this);
        application, utils::localize.get("app_calendar_new_edit_event_allday"), [this](bool isChecked) {
            isChecked ? createTimeItems() : eraseTimeItems();
            const auto it = std::find(std::begin(internalData), std::end(internalData), allDayEventCheckBox);
            list->rebuildList(style::listview::RebuildType::OnPageElement, std::distance(std::begin(internalData), it));
        });

    dateItem = new gui::CalendarDateItem();

    startTime = new gui::CalendarTimeItem(
        utils::localize.get("app_calendar_new_edit_event_start"),
        gui::TimeWidget::Type::Start,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text, false); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); });

    endTime = new gui::CalendarTimeItem(
        utils::localize.get("app_calendar_new_edit_event_end"),
        gui::TimeWidget::Type::End,
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text, false); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); });

    reminder = new gui::SeveralOptionsItem(
        application,
        utils::localize.get("app_calendar_event_detail_reminder"),


@@ 98,24 73,23 @@ void NewEditEventModel::createData(bool allDayEvent)
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text, false); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); });

    startTime->setConnectionToSecondItem(endTime);
    endTime->setConnectionToSecondItem(startTime);

    startTime->setConnectionToDateItem(dateItem);
    endTime->setConnectionToDateItem(dateItem);

    allDayEventCheckBox->setConnectionToDateItem(dateItem->getDateWidget());

    internalData.push_back(eventNameInput);
    internalData.push_back(allDayEventCheckBox);
    internalData.push_back(dateItem);
    if (!allDayEvent) {
        internalData.push_back(startTime);
        internalData.push_back(endTime);
    }
    internalData.push_back(reminder);
    internalData.push_back(repeat);

    if (!allDayEvent) {
        createTimeItems();
    }
    else {
        startTimeBuffer +=
            TimePointToHourMinSec(TimePointNow()).hours() + TimePointToHourMinSec(TimePointNow()).minutes();
        endTimeBuffer = startTimeBuffer + std::chrono::hours(1);
    }

    for (auto &item : internalData) {
        item->deleteByList = false;
    }


@@ 123,38 97,17 @@ void NewEditEventModel::createData(bool allDayEvent)

void NewEditEventModel::loadData(std::shared_ptr<EventsRecord> record)
{
    list->clear();
    eraseInternalData();
    auto start_time    = TimePointToHourMinSec(record->date_from);
    auto end_time      = TimePointToHourMinSec(record->date_till);
    auto isAllDayEvent = [&]() -> bool {
        return start_time.hours().count() == 0 && start_time.minutes().count() == 0 &&
               end_time.hours().count() == utils::time::Locale::max_hour_24H_mode &&
               end_time.minutes().count() == utils::time::Locale::max_minutes;
    };
    clearData();
    startTimeBuffer = record->date_from;
    endTimeBuffer   = record->date_till;

    createData(isAllDayEvent());
    createData(gui::allDayEvents::isAllDayEvent(startTimeBuffer, endTimeBuffer));

    for (auto &item : internalData) {
        if (item->onLoadCallback) {
            item->onLoadCallback(record);
        }
    }

    if (isAllDayEvent()) {
        record->date_from = record->date_from - TimePointToHourMinSec(record->date_from).hours() -
                            TimePointToHourMinSec(record->date_from).minutes() +
                            TimePointToHourMinSec(TimePointNow()).hours() +
                            TimePointToHourMinSec(TimePointNow()).minutes();
        record->date_till = record->date_from + std::chrono::hours(1);
        if (startTime->onLoadCallback) {
            startTime->onLoadCallback(record);
        }
        if (endTime->onLoadCallback) {
            endTime->onLoadCallback(record);
        }
    }

    list->rebuildList();
}



@@ 165,32 118,6 @@ void NewEditEventModel::loadRepeat(const std::shared_ptr<EventsRecord> &record)
    }
}

void NewEditEventModel::loadDataWithoutTimeItem()
{
    internalData.erase(std::find(internalData.begin(), internalData.end(), startTime));
    internalData.erase(std::find(internalData.begin(), internalData.end(), endTime));
    list->rebuildList();
}

void NewEditEventModel::reloadDataWithTimeItem()
{
    internalData.clear();

    internalData.push_back(eventNameInput);
    internalData.push_back(allDayEventCheckBox);
    internalData.push_back(dateItem);
    internalData.push_back(startTime);
    internalData.push_back(endTime);
    internalData.push_back(reminder);
    internalData.push_back(repeat);

    for (auto &item : internalData) {
        item->deleteByList = false;
    }

    list->rebuildList();
}

void NewEditEventModel::saveData(std::shared_ptr<EventsRecord> event, EventAction action)
{
    for (auto &item : internalData) {


@@ 247,7 174,57 @@ void NewEditEventModel::saveData(std::shared_ptr<EventsRecord> event, EventActio
            application->returnToPreviousWindow();
        }
    }
    clearData();
}

void NewEditEventModel::createTimeItems()
{
    auto create = [this](gui::CalendarTimeItem *&item, const std::string &description, gui::TimeWidget::Type type) {
        if (item == nullptr) {
            auto app = application;
            item     = new gui::CalendarTimeItem(
                description,
                type,
                [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text, false); },
                [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
                startTimeBuffer,
                endTimeBuffer);

            item->deleteByList = false;
            item->setConnectionToDateItem(dateItem);
            internalData.insert(std::find(internalData.begin(), internalData.end(), reminder), item);
        }
    };

    create(startTime, utils::localize.get("app_calendar_new_edit_event_start"), gui::TimeWidget::Type::Start);
    create(endTime, utils::localize.get("app_calendar_new_edit_event_end"), gui::TimeWidget::Type::End);

    startTime->setConnectionToSecondItem(endTime);
    endTime->setConnectionToSecondItem(startTime);
}

void NewEditEventModel::eraseTimeItems()
{
    auto erase = [this](gui::CalendarTimeItem *&item) {
        if (item != nullptr) {
            item->deleteByList = true;
            internalData.erase(std::find(internalData.begin(), internalData.end(), item));
            item = nullptr;
        }
    };

    startTimeBuffer = startTime->getFromTillDate()->from;
    endTimeBuffer   = endTime->getFromTillDate()->till;
    erase(startTime);
    erase(endTime);
}

void NewEditEventModel::clearData()
{
    list->clear();
    eraseInternalData();
    startTime       = nullptr;
    endTime         = nullptr;
    startTimeBuffer = TimePoint();
    endTimeBuffer   = TimePoint();
}

M module-apps/application-calendar/models/NewEditEventModel.hpp => module-apps/application-calendar/models/NewEditEventModel.hpp +19 -21
@@ 3,51 3,49 @@

#pragma once
#include "Application.hpp"
#include <application-calendar/widgets/CalendarDateItem.hpp>
#include <application-calendar/widgets/CalendarTimeItem.hpp>
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/widgets/TextWithLabelItem.hpp"
#include "application-calendar/widgets/SeveralOptionsItem.hpp"
#include "InternalModel.hpp"
#include <ListItemProvider.hpp>
#include <application-calendar/widgets/CalendarListItem.hpp>
#include <application-calendar/data/CalendarData.hpp>

namespace gui
{
    class NewEventCheckBoxWithLabel; // fw declaration
}
    class TextWithLabelItem;
    class NewEventCheckBoxWithLabel;
    class CalendarDateItem;
    class CalendarTimeItem;
    class SeveralOptionsItem;
} // namespace gui

class NewEditEventModel : public app::InternalModel<gui::CalendarListItem *>, public gui::ListItemProvider
{
    app::Application *application = nullptr;
    bool mode24H                  = false;

    gui::NewEventCheckBoxWithLabel *allDayEventCheckBox = nullptr;
    TimePoint startTimeBuffer;
    TimePoint endTimeBuffer;

    gui::TextWithLabelItem *eventNameInput              = nullptr;
    gui::NewEventCheckBoxWithLabel *allDayEventCheckBox = nullptr;
    gui::CalendarDateItem *dateItem  = nullptr;
    gui::CalendarTimeItem *startTime = nullptr;
    gui::CalendarTimeItem *endTime   = nullptr;
    gui::SeveralOptionsItem *reminder                   = nullptr;
    gui::SeveralOptionsItem *repeat                     = nullptr;

    gui::SeveralOptionsItem *reminder      = nullptr;
    gui::SeveralOptionsItem *repeat        = nullptr;
    gui::TextWithLabelItem *eventNameInput = nullptr;
    void createData(bool allDayEvent);
    void createTimeItems();
    void eraseTimeItems();
    void clearData();

  public:
    NewEditEventModel(app::Application *app, bool mode24H = false);
    explicit NewEditEventModel(app::Application *app);

    void loadData(std::shared_ptr<EventsRecord> record);
    void loadRepeat(const std::shared_ptr<EventsRecord> &record);
    void loadDataWithoutTimeItem();
    void reloadDataWithTimeItem();
    void saveData(std::shared_ptr<EventsRecord> event, EventAction action);

    [[nodiscard]] unsigned int getMinimalItemHeight() const override;
    [[nodiscard]] unsigned int requestRecordsCount() override;
    gui::ListItem *getItem(gui::Order order) override;
    void requestRecords(const uint32_t offset, const uint32_t limit) override;

    uint32_t getRepeatOptionValue();
    void setRepeatOptionValue(const uint32_t &value);

  private:
    void createData(bool allDayEvent);
};

M module-apps/application-calendar/widgets/CalendarTimeItem.cpp => module-apps/application-calendar/widgets/CalendarTimeItem.cpp +14 -1
@@ 14,7 14,9 @@ namespace gui
    CalendarTimeItem::CalendarTimeItem(const std::string &description,
                                       TimeWidget::Type type,
                                       const std::function<void(const UTF8 &text)> &bottomBarTemporaryMode,
                                       const std::function<void()> &bottomBarRestoreFromTemporaryMode)
                                       const std::function<void()> &bottomBarRestoreFromTemporaryMode,
                                       TimePoint dateFrom,
                                       TimePoint dateTill)
    {
        setMinimumSize(style::window::default_body_width, date_and_time::height);
        setEdges(RectangleEdge::None);


@@ 24,6 26,10 @@ namespace gui
        vBox->setEdges(RectangleEdge::None);

        timeWidget = new TimeWidget(vBox, description, type, bottomBarTemporaryMode, bottomBarRestoreFromTemporaryMode);
        timeWidget->loadData(std::chrono::hours(TimePointToHour24H(dateFrom)),
                             std::chrono::minutes(TimePointToMin(dateFrom)),
                             std::chrono::hours(TimePointToHour24H(dateTill)),
                             std::chrono::minutes(TimePointToMin(dateTill)));

        onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
            timeWidget->loadData(std::chrono::hours(TimePointToHour24H(event->date_from)),


@@ 44,6 50,13 @@ namespace gui
        passDefaultCallbacksFromListItem(this, vBox);
    }

    auto CalendarTimeItem::getFromTillDate() const -> std::shared_ptr<utils::time::FromTillDate>
    {
        auto fromTillDate = std::make_shared<utils::time::FromTillDate>();
        timeWidget->saveData(fromTillDate);
        return fromTillDate;
    }

    void CalendarTimeItem::setConnectionToSecondItem(CalendarTimeItem *item)
    {
        timeWidget->setConnectionToSecondItem(item->timeWidget);

M module-apps/application-calendar/widgets/CalendarTimeItem.hpp => module-apps/application-calendar/widgets/CalendarTimeItem.hpp +4 -1
@@ 15,10 15,13 @@ namespace gui
        CalendarTimeItem(const std::string &description,
                         TimeWidget::Type type,
                         const std::function<void(const UTF8 &text)> &bottomBarTemporaryMode,
                         const std::function<void()> &bottomBarRestoreFromTemporaryMode);
                         const std::function<void()> &bottomBarRestoreFromTemporaryMode,
                         TimePoint dateFrom,
                         TimePoint dateTill);

        void setConnectionToSecondItem(CalendarTimeItem *item);
        void setConnectionToDateItem(CalendarDateItem *item);
        auto getFromTillDate() const -> std::shared_ptr<utils::time::FromTillDate>;

      private:
        TimeWidget *timeWidget = nullptr;

M module-apps/application-calendar/widgets/NewEventCheckBoxWithLabel.cpp => module-apps/application-calendar/widgets/NewEventCheckBoxWithLabel.cpp +16 -14
@@ 3,14 3,15 @@

#include "NewEventCheckBoxWithLabel.hpp"
#include "AppWindow.hpp"
#include "InputEvent.hpp"

namespace gui
{

    NewEventCheckBoxWithLabel::NewEventCheckBoxWithLabel(app::Application *application,
                                                         const std::string &description,
                                                         NewEditEventModel *model)
        : CheckBoxWithLabelItem(application, description, nullptr), model(model)
                                                         OnCheckCallback onCheck)
        : CheckBoxWithLabelItem(application, description, nullptr), onCheck(std::move(onCheck))
    {
        app = application;
        assert(app != nullptr);


@@ 38,13 39,9 @@ namespace gui
            if (event.state != gui::InputEvent::State::keyReleasedShort) {
                return false;
            }
            if (checkBox->isChecked() && event.keyCode == gui::KeyCode::KEY_LF) {
                LOG_DEBUG("reloadDataWithTimeItem");
                model->reloadDataWithTimeItem();
            }
            else if (!checkBox->isChecked() && event.keyCode == gui::KeyCode::KEY_LF) {
                LOG_DEBUG("loadDataWithoutTimeItem");
                model->loadDataWithoutTimeItem();

            if (event.is(gui::KeyCode::KEY_LF)) {
                onCheck(checkBox->isChecked());
            }

            if (checkBox->onInput(event)) {


@@ 57,11 54,7 @@ namespace gui
        };

        onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
            auto start_time = TimePointToHourMinSec(event->date_from);
            auto end_time   = TimePointToHourMinSec(event->date_till);
            if (start_time.hours().count() == 0 && start_time.minutes().count() == 0 &&
                end_time.hours().count() == utils::time::Locale::max_hour_24H_mode &&
                end_time.minutes().count() == utils::time::Locale::max_minutes) {
            if (allDayEvents::isAllDayEvent(event->date_from, event->date_till)) {
                checkBox->setImageVisible(true);
            }
        };


@@ 79,4 72,13 @@ namespace gui
        dateItem = item;
    }

    bool allDayEvents::isAllDayEvent(TimePoint start, TimePoint end)
    {
        auto startTime = TimePointToHourMinSec(start);
        auto endTime   = TimePointToHourMinSec(end);
        return startTime.hours().count() == 0 && startTime.minutes().count() == 0 &&
               endTime.hours().count() == utils::time::Locale::max_hour_24H_mode &&
               endTime.minutes().count() == utils::time::Locale::max_minutes;
    }

} /* namespace gui */

M module-apps/application-calendar/widgets/NewEventCheckBoxWithLabel.hpp => module-apps/application-calendar/widgets/NewEventCheckBoxWithLabel.hpp +9 -4
@@ 3,13 3,14 @@

#pragma once
#include "CheckBoxWithLabelItem.hpp"
#include "application-calendar/models/NewEditEventModel.hpp"
#include <widgets/DateWidget.hpp>

namespace gui
{
    class NewEventCheckBoxWithLabel : public CheckBoxWithLabelItem
    {
        NewEditEventModel *model = nullptr;
        using OnCheckCallback     = std::function<void(bool)>;
        OnCheckCallback onCheck   = nullptr;
        app::Application *app    = nullptr;
        gui::DateWidget *dateItem = nullptr;
        void applyCallbacks() override;


@@ 17,10 18,14 @@ namespace gui
      public:
        NewEventCheckBoxWithLabel(app::Application *application,
                                  const std::string &description,
                                  NewEditEventModel *model  = nullptr);
        virtual ~NewEventCheckBoxWithLabel() override = default;
                                  OnCheckCallback onCheck);

        void setConnectionToDateItem(gui::DateWidget *item);
    };

    namespace allDayEvents
    {
        bool isAllDayEvent(TimePoint start, TimePoint end);
    }

} /* namespace gui */

M module-apps/application-calendar/windows/AllEventsWindow.cpp => module-apps/application-calendar/windows/AllEventsWindow.cpp +3 -17
@@ 74,12 74,6 @@ namespace gui

    bool AllEventsWindow::onInput(const gui::InputEvent &inputEvent)
    {
        if (inputEvent.keyCode == gui::KeyCode::KEY_RF &&
            inputEvent.state == gui::InputEvent::State::keyReleasedShort) {
            LOG_DEBUG("Switch to desktop");
            app::manager::Controller::switchBack(application);
        }

        if (AppWindow::onInput(inputEvent)) {
            return true;
        }


@@ 88,26 82,18 @@ namespace gui
            return false;
        }

        if (inputEvent.keyCode == gui::KeyCode::KEY_LEFT) {
        if (inputEvent.is(gui::KeyCode::KEY_LEFT)) {
            LOG_DEBUG("Switch to new event window");
            std::unique_ptr<EventRecordData> data = std::make_unique<EventRecordData>();
            data->setDescription(style::window::calendar::new_event);
            auto event       = std::make_shared<EventsRecord>();
            event->date_from = dateFilter;
            event->date_till = dateFilter + std::chrono::hours(utils::time::Locale::max_hour_24H_mode) +
                               std::chrono::minutes(utils::time::Locale::max_minutes);
            data->setData(event);
            auto data = std::make_unique<EventRecordData>(std::move(event));
            data->setDescription(style::window::calendar::new_event);
            application->switchWindow(
                style::window::calendar::name::new_edit_event, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;
        }

        if (inputEvent.keyCode == gui::KeyCode::KEY_LF) {
            application->switchWindow(gui::name::window::main_window);
            LOG_DEBUG("Switch to month view - main window");
            return true;
        }

        return false;
    }


M module-apps/application-calendar/windows/DayEventsWindow.cpp => module-apps/application-calendar/windows/DayEventsWindow.cpp +6 -8
@@ 95,16 95,14 @@ namespace gui
            return false;
        }

        if (inputEvent.keyCode == gui::KeyCode::KEY_LEFT) {
        if (inputEvent.is(gui::KeyCode::KEY_LEFT)) {
            LOG_DEBUG("Switch to new window - edit window");
            std::unique_ptr<EventRecordData> data = std::make_unique<EventRecordData>();
            auto event       = std::make_shared<EventsRecord>();
            event->date_from = filterFrom;
            event->date_till = filterFrom + std::chrono::hours(utils::time::Locale::max_hour_24H_mode) +
                               std::chrono::minutes(utils::time::Locale::max_minutes);
            auto data = std::make_unique<EventRecordData>(std::move(event));
            data->setDescription(style::window::calendar::new_event);
            auto rec       = new EventsRecord();
            rec->date_from = filterFrom;
            rec->date_till = filterFrom + std::chrono::hours(utils::time::Locale::max_hour_24H_mode) +
                             std::chrono::minutes(utils::time::Locale::max_minutes);
            auto event = std::make_shared<EventsRecord>(*rec);
            data->setData(event);
            application->switchWindow(
                style::window::calendar::name::new_edit_event, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;

M module-apps/widgets/TimeWidget.cpp => module-apps/widgets/TimeWidget.cpp +5 -5
@@ 209,12 209,12 @@ namespace gui
        this->dateItem = item;
    }

    bool TimeWidget::isPm(const std::string &text)
    bool TimeWidget::isPm(const std::string &text) const
    {
        return !(text == timeConstants::before_noon);
    }

    bool TimeWidget::validateHour()
    bool TimeWidget::validateHour() const
    {
        if (type == Type::End) {
            if (secondItem == nullptr) {


@@ 282,7 282,7 @@ namespace gui
    void TimeWidget::validateHourFor12hMode(std::chrono::hours start_hour,
                                            std::chrono::minutes end_hour,
                                            uint32_t start_minutes,
                                            uint32_t end_minutes)
                                            uint32_t end_minutes) const
    {
        if (start_hour > end_hour || (start_hour == end_hour && start_minutes > end_minutes)) {
            auto hour = start_hour.count() + 1;


@@ 314,7 314,7 @@ namespace gui
    void TimeWidget::validateHourFor24hMode(std::chrono::hours start_hour,
                                            std::chrono::minutes end_hour,
                                            uint32_t start_minutes,
                                            uint32_t end_minutes)
                                            uint32_t end_minutes) const
    {
        if (start_hour > end_hour || (start_hour == end_hour && start_minutes > end_minutes)) {
            auto hour = start_hour.count() + 1;


@@ 417,7 417,7 @@ namespace gui
        }
    }

    bool TimeWidget::saveData(std::shared_ptr<utils::time::FromTillDate> fromTillDate)
    bool TimeWidget::saveData(std::shared_ptr<utils::time::FromTillDate> fromTillDate) const
    {
        if (!validateHour()) {
            return false;

M module-apps/widgets/TimeWidget.hpp => module-apps/widgets/TimeWidget.hpp +6 -6
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 35,7 35,7 @@ namespace gui
                      const std::chrono::minutes &minutesFrom,
                      const std::chrono::hours &hoursTill,
                      const std::chrono::minutes &minutesTill);
        bool saveData(std::shared_ptr<utils::time::FromTillDate> fromTillDate);
        bool saveData(std::shared_ptr<utils::time::FromTillDate> fromTillDate) const;
        virtual ~TimeWidget() override = default;

        void setConnectionToSecondItem(TimeWidget *item);


@@ 63,15 63,15 @@ namespace gui
        void setTime(int keyValue, Label &item);
        void onInputCallback(Label &timeInput);
        void clearInput(Label &timeInput);
        bool isPm(const std::string &text);
        bool validateHour();
        inline bool isPm(const std::string &text) const;
        bool validateHour() const;
        void validateHourFor12hMode(std::chrono::hours start_hour,
                                    std::chrono::minutes end_hour,
                                    uint32_t start_minutes,
                                    uint32_t end_minutes);
                                    uint32_t end_minutes) const;
        void validateHourFor24hMode(std::chrono::hours start_hour,
                                    std::chrono::minutes end_hour,
                                    uint32_t start_minutes,
                                    uint32_t end_minutes);
                                    uint32_t end_minutes) const;
    };
} /* namespace gui */

M module-services/service-time/timeEvents/CalendarTimeEvents.cpp => module-services/service-time/timeEvents/CalendarTimeEvents.cpp +3 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-time/CalendarTimeEvents.hpp>


@@ 84,10 84,9 @@ namespace stm

    void CalendarTimeEvents::invokeEvent()
    {
        std::unique_ptr<EventRecordData> eventData = std::make_unique<EventRecordData>();
        eventData->setDescription(style::window::calendar::name::event_reminder_window);
        auto event = std::make_shared<EventsRecord>(eventRecord);
        eventData->setData(event);
        auto eventData = std::make_unique<EventRecordData>(std::move(event));
        eventData->setDescription(style::window::calendar::name::event_reminder_window);

        app::manager::Controller::sendAction(service(), app::manager::actions::ShowReminder, std::move(eventData));
    }