~aleteoryx/muditaos

65b4e9ad0f50feecdd3330be09cc95d44485d9e6 — Tomas Rogala 5 years ago f66212e
[EGD-3469] PR changes
79 files changed, 2734 insertions(+), 861 deletions(-)

A art/phone/common/dots/event_dot.png
M changelog.md
A image/assets/images/event_dot.vpi
M image/assets/lang/lang_en.json
M module-apps/application-calendar/ApplicationCalendar.cpp
M module-apps/application-calendar/ApplicationCalendar.hpp
M module-apps/application-calendar/CMakeLists.txt
A module-apps/application-calendar/data/CalendarData.cpp
A module-apps/application-calendar/data/CalendarData.hpp
A module-apps/application-calendar/data/OptionParser.hpp
A module-apps/application-calendar/data/TimeDisplayParser.hpp
A module-apps/application-calendar/data/dateCommon.hpp
M module-apps/application-calendar/models/AllEventsModel.cpp
M module-apps/application-calendar/models/AllEventsModel.hpp
D module-apps/application-calendar/models/CalendarEventsModel.cpp
M module-apps/application-calendar/models/CustomRepeatModel.cpp
M module-apps/application-calendar/models/CustomRepeatModel.hpp
A module-apps/application-calendar/models/DayEventsInternalModel.cpp
R module-apps/application-calendar/models/{DayEventsModel => DayEventsInternalModel}.hpp
D module-apps/application-calendar/models/DayEventsModel.cpp
M module-apps/application-calendar/models/EventDetailModel.cpp
M module-apps/application-calendar/models/EventDetailModel.hpp
M module-apps/application-calendar/models/MonthModel.cpp
M module-apps/application-calendar/models/MonthModel.hpp
M module-apps/application-calendar/models/NewEditEventModel.cpp
M module-apps/application-calendar/models/NewEditEventModel.hpp
M module-apps/application-calendar/widgets/AllEventsItem.cpp
M module-apps/application-calendar/widgets/AllEventsItem.hpp
M module-apps/application-calendar/widgets/CalendarListItem.hpp
M module-apps/application-calendar/widgets/CalendarStyle.hpp
M module-apps/application-calendar/widgets/CheckBoxWithLabelItem.cpp
M module-apps/application-calendar/widgets/CheckBoxWithLabelItem.hpp
M module-apps/application-calendar/widgets/DayEventsItem.cpp
M module-apps/application-calendar/widgets/DayEventsItem.hpp
A module-apps/application-calendar/widgets/DayLabel.cpp
A module-apps/application-calendar/widgets/DayLabel.hpp
M module-apps/application-calendar/widgets/EventDetailDescriptionItem.cpp
M module-apps/application-calendar/widgets/EventTimeItem.cpp
M module-apps/application-calendar/widgets/EventTimeItem.hpp
A module-apps/application-calendar/widgets/MonthBox.cpp
A module-apps/application-calendar/widgets/MonthBox.hpp
R module-apps/application-calendar/widgets/{CheckBoxWithLabelAndModel => NewEventCheckBoxWithLabel}.cpp
R module-apps/application-calendar/widgets/{CheckBoxWithLabelAndModel => NewEventCheckBoxWithLabel}.hpp
M module-apps/application-calendar/widgets/RepeatAndReminderItem.cpp
M module-apps/application-calendar/widgets/RepeatAndReminderItem.hpp
M module-apps/application-calendar/widgets/SeveralOptionsItem.cpp
M module-apps/application-calendar/widgets/SeveralOptionsItem.hpp
M module-apps/application-calendar/widgets/TextWithLabelItem.cpp
M module-apps/application-calendar/windows/AllEventsWindow.cpp
M module-apps/application-calendar/windows/AllEventsWindow.hpp
M module-apps/application-calendar/windows/CalendarEventsOptionsWindow.cpp
M module-apps/application-calendar/windows/CalendarEventsOptionsWindow.hpp
M module-apps/application-calendar/windows/CalendarMainWindow.cpp
M module-apps/application-calendar/windows/CalendarMainWindow.hpp
M module-apps/application-calendar/windows/CustomRepeatWindow.cpp
M module-apps/application-calendar/windows/CustomRepeatWindow.hpp
M module-apps/application-calendar/windows/DayEventsWindow.cpp
M module-apps/application-calendar/windows/DayEventsWindow.hpp
M module-apps/application-calendar/windows/EventDetailWindow.cpp
M module-apps/application-calendar/windows/EventDetailWindow.hpp
M module-apps/application-calendar/windows/NewEditEventWindow.cpp
M module-apps/application-calendar/windows/NewEditEventWindow.hpp
M module-apps/application-desktop/windows/DesktopMainWindow.cpp
M module-db/CMakeLists.txt
M module-db/Interface/EventsRecord.cpp
M module-db/Interface/EventsRecord.hpp
M module-db/Tables/EventsTable.cpp
M module-db/Tables/EventsTable.hpp
M module-db/queries/calendar/QueryEventsEdit.cpp
M module-db/queries/calendar/QueryEventsEdit.hpp
A module-db/queries/calendar/QueryEventsGetAllLimited.cpp
A module-db/queries/calendar/QueryEventsGetAllLimited.hpp
M module-db/queries/calendar/QueryEventsGetFiltered.cpp
M module-db/queries/calendar/QueryEventsGetFiltered.hpp
M module-db/queries/calendar/QueryEventsRemove.cpp
M module-db/tests/EventsRecord_tests.cpp
M module-db/tests/EventsTable_tests.cpp
M module-gui/gui/widgets/CheckBox.cpp
M module-utils/time/time_locale.hpp
A art/phone/common/dots/event_dot.png => art/phone/common/dots/event_dot.png +0 -0
M changelog.md => changelog.md +5 -0
@@ 4,6 4,11 @@

### Added

* `[calendar]` Communication between windows.
* `[calendar]` Add/Edit/Remove events functionality.
* `[calendar]` Display events in day window and allEvents window.
* `[calendar]` Marking days witch contains events in Calendar Main Window.
* `[calendar]` Add repeated events.
* `[desktop]` info on how to unlock
* `[settings]` pin change option in settings main window
* `[phonebook]` Make SAVE button appear when at least one field is fulfilled.

A image/assets/images/event_dot.vpi => image/assets/images/event_dot.vpi +0 -0
M image/assets/lang/lang_en.json => image/assets/lang/lang_en.json +3 -0
@@ 58,6 58,8 @@
    "locale_24hour_min" : "%H:%M",
    "locale_date_full" : "%m/%d/%y",
    "locale_date_short" : "%d/%m",
    "common_AM" : "AM",
    "common_PM" : "PM",

    "duration_min_0sec" : "%M:%0S",
    "duration_0min_0sec" : "%0M:%0S",


@@ 98,6 100,7 @@
    "app_calendar_edit": "EDIT",
    "app_calendar_new_edit_event_name": "Event name",
    "app_calendar_new_edit_event_allday": "All day event",
    "app_calendar_all_day": "All day",
    "app_calendar_new_edit_event_start": "Start",
    "app_calendar_new_edit_event_end": "End",


M module-apps/application-calendar/ApplicationCalendar.cpp => module-apps/application-calendar/ApplicationCalendar.cpp +77 -17
@@ 6,23 6,35 @@
#include "windows/EventDetailWindow.hpp"
#include "windows/NewEditEventWindow.hpp"
#include "windows/CustomRepeatWindow.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "NoEvents.hpp"
#include "Dialog.hpp"
#include <time/time_conversion.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <module-db/queries/calendar/QueryEventsGet.hpp>
#include <module-db/queries/calendar/QueryEventsAdd.hpp>
#include <module-db/queries/calendar/QueryEventsEdit.hpp>
#include <module-db/queries/calendar/QueryEventsGetAll.hpp>
#include <module-db/queries/calendar/QueryEventsRemove.hpp>
#include <module-db/queries/calendar/QueryEventsGetFiltered.hpp>
#include <module-services/service-db/messages/QueryMessage.hpp>
#include <messages/QueryMessage.hpp>
#include <map>

namespace app
{
    const map<Reminder, const char *> ApplicationCalendar::reminderOptions = {
        {Reminder::never, "app_calendar_reminder_never"},
        {Reminder::event_time, "app_calendar_reminder_event_time"},
        {Reminder::five_min_before, "app_calendar_reminder_5_min_before"},
        {Reminder::fifteen_min_before, "app_calendar_reminder_15_min_before"},
        {Reminder::thirty_min_before, "app_calendar_reminder_30_min_before"},
        {Reminder::one_hour_before, "app_calendar_reminder_1_hour_before"},
        {Reminder::two_hour_before, "app_calendar_reminder_2_hour_before"},
        {Reminder::one_day_before, "app_calendar_reminder_1_day_before"},
        {Reminder::two_days_before, "app_calendar_reminder_2_days_before"},
        {Reminder::one_week_before, "app_calendar_reminder_1_week_before"}};

    const map<Repeat, const char *> ApplicationCalendar::repeatOptions = {
        {Repeat::never, "app_calendar_repeat_never"},
        {Repeat::daily, "app_calendar_repeat_daily"},
        {Repeat::weekly, "app_calendar_repeat_weekly"},
        {Repeat::two_weeks, "app_calendar_repeat_two_weeks"},
        {Repeat::month, "app_calendar_repeat_month"},
        {Repeat::year, "app_calendar_repeat_year"},
        {Repeat::custom, "app_calendar_repeat_custom"}};

    ApplicationCalendar::ApplicationCalendar(std::string name,
                                             std::string parent,


@@ 33,20 45,38 @@ namespace app

    sys::Message_t ApplicationCalendar::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
    {
        return Application::DataReceivedHandler(msgl);
        auto retMsg = Application::DataReceivedHandler(msgl);
        // if message was handled by application's template there is no need to process further.
        if (retMsg && (dynamic_cast<sys::ResponseMessage *>(retMsg.get())->retCode == sys::ReturnCodes::Success)) {
            return retMsg;
        }
        // this variable defines whether message was processed.
        bool handled = false;
        // handle database response
        if (resp != nullptr) {
            handled = true;
            switch (resp->responseTo) {
            case MessageType::DBQuery: {
                if (getCurrentWindow()->onDatabaseMessage(resp))
                    refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
            } break;
            default:
                break;
            }
        }
        if (handled) {
            return std::make_shared<sys::ResponseMessage>();
        }
        else {
            return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Unresolved);
        }
    }

    sys::ReturnCodes ApplicationCalendar::InitHandler()
    {
        auto timestamp       = new utils::time::Timestamp();
        applicationStartTime = timestamp->getTime();
        utils::time::Timestamp timestamp;
        applicationStartTime = timestamp.getTime();
        auto ret             = Application::InitHandler();
        EventsRecord event(EventsTableRow{{1}, "TEST", "TEST", 191020142, 191020153, 1, 2, 1});
        EventsRecord event2(EventsTableRow{{2}, "TEST2", "TEST2", 191020152, 191020163, 1, 2, 1});
        DBServiceAPI::GetQuery(this, db::Interface::Name::Events, std::make_unique<db::query::events::Add>(event));
        DBServiceAPI::GetQuery(this, db::Interface::Name::Events, std::make_unique<db::query::events::Add>(event));
        DBServiceAPI::GetQuery(this, db::Interface::Name::Events, std::make_unique<db::query::events::Add>(event2));
        DBServiceAPI::GetQuery(this, db::Interface::Name::Events, std::make_unique<db::query::events::Add>(event2));
        createUserInterface();
        return ret;
    }


@@ 89,4 119,34 @@ namespace app
    void ApplicationCalendar::destroyUserInterface()
    {}

    void ApplicationCalendar::switchToNoEventsWindow(const std::string &title,
                                                     const TimePoint &dateFilter,
                                                     const std::string &goBackWindow)
    {
        auto dialog = dynamic_cast<gui::NoEvents *>(getWindow(style::window::calendar::name::no_events_window));
        assert(dialog != nullptr);
        auto meta  = dialog->meta;
        meta.text  = "app_calendar_no_events_information";
        meta.title = title;
        meta.icon  = "phonebook_empty_grey_circle_W_G";

        meta.action = [=]() -> 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;
            eventData->setData(event);
            eventData->setWindowName(goBackWindow);
            switchWindow(
                style::window::calendar::name::new_edit_event, gui::ShowMode::GUI_SHOW_INIT, std::move(eventData));
            return true;
        };
        dialog->update(meta);
        switchWindow(gui::name::window::main_window);
        switchWindow(dialog->getName());
        LOG_DEBUG("Switch to no events window");
    }

} /* namespace app */

M module-apps/application-calendar/ApplicationCalendar.hpp => module-apps/application-calendar/ApplicationCalendar.hpp +9 -1
@@ 4,6 4,8 @@
#include "Service/Message.hpp"
#include "SystemManager/SystemManager.hpp"
#include "gui/widgets/Label.hpp"
#include <module-apps/application-calendar/data/dateCommon.hpp>
#include "application-calendar/widgets/CalendarStyle.hpp"

namespace app
{


@@ 13,6 15,7 @@ namespace app
    class ApplicationCalendar : public Application
    {
        time_t applicationStartTime = 0;
        int eventShift              = 0;

      public:
        ApplicationCalendar(std::string name,


@@ 35,6 38,11 @@ namespace app

        void createUserInterface() override;
        void destroyUserInterface() override;
    };
        void switchToNoEventsWindow(const std::string &title,
                                    const TimePoint &dateFilter,
                                    const std::string &goBackWindow);

        static const std::map<Reminder, const char *> reminderOptions;
        static const std::map<Repeat, const char *> repeatOptions;
    };
} /* namespace app */

M module-apps/application-calendar/CMakeLists.txt => module-apps/application-calendar/CMakeLists.txt +11 -5
@@ 2,6 2,8 @@ target_sources( ${PROJECT_NAME}

	PRIVATE
		"${CMAKE_CURRENT_LIST_DIR}/ApplicationCalendar.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/data/CalendarData.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/MonthModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/CalendarMainWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/DayEventsWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/CalendarEventsOptionsWindow.cpp"


@@ 9,13 11,12 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/windows/EventDetailWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/NewEditEventWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/CustomRepeatWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/DayEventsModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/AllEventsModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/EventDetailModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/windows/EventDetailWindow.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/MonthModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/CustomRepeatModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/NewEditEventModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/DayEventsInternalModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/DayEventsItem.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/AllEventsItem.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/CalendarListView.cpp"


@@ 25,11 26,16 @@ target_sources( ${PROJECT_NAME}
		"${CMAKE_CURRENT_LIST_DIR}/widgets/EventTimeItem.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/SeveralOptionsItem.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/TextWithLabelItem.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/CheckBoxWithLabelAndModel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/NewEventCheckBoxWithLabel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/DayLabel.cpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/MonthBox.cpp"
	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}/ApplicationCalendar.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/DayEventsModel.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/models/MonthModel.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/widgets/CalendarListItem.hpp"

		"${CMAKE_CURRENT_LIST_DIR}/widgets/CalendarStyle.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/data/OptionParser.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/data/CalendarData.hpp"
		"${CMAKE_CURRENT_LIST_DIR}/data/TimeDisplayParser.hpp"
)


A module-apps/application-calendar/data/CalendarData.cpp => module-apps/application-calendar/data/CalendarData.cpp +32 -0
@@ 0,0 1,32 @@
#include "CalendarData.hpp"
#include "dateCommon.hpp"

WeekDaysRepeatData::WeekDaysRepeatData()
{
    for (uint32_t i = 0; i < style::window::calendar::week_days_number; i++) {
        weekDays[i] = false;
    }
}

[[nodiscard]] auto WeekDaysRepeatData::getData(const uint32_t &weekDay) const -> bool
{
    if (weekDay >= style::window::calendar::week_days_number) {
        LOG_ERROR("Weekday out of range (%d)", static_cast<int>(weekDay));
        return false;
    }
    return weekDays[weekDay];
}

void WeekDaysRepeatData::setData(const uint32_t &weekDay)
{
    if (weekDay >= style::window::calendar::week_days_number) {
        LOG_ERROR("Weekday out of range (%d)", static_cast<int>(weekDay));
        return;
    }
    if (weekDays[weekDay]) {
        weekDays[weekDay] = false;
    }
    else {
        weekDays[weekDay] = true;
    }
}

A module-apps/application-calendar/data/CalendarData.hpp => module-apps/application-calendar/data/CalendarData.hpp +98 -0
@@ 0,0 1,98 @@
#pragma once
#include "module-db/Interface/EventsRecord.hpp"
#include <module-gui/gui/SwitchData.hpp>
#include "application-calendar/widgets/CalendarStyle.hpp"

class EventRecordData : public gui::SwitchData
{
  protected:
    std::string backWindowName;
    std::shared_ptr<EventsRecord> record;

  public:
    EventRecordData() = default;
    EventRecordData(std::shared_ptr<EventsRecord> record) : record{std::move(record)} {};
    virtual ~EventRecordData() = default;
    std::shared_ptr<EventsRecord> getData()
    {
        return record;
    };
    virtual void setData(std::shared_ptr<EventsRecord> rec)
    {
        record = std::move(rec);
    };
    std::string getWindowName()
    {
        return backWindowName;
    };
    virtual void setWindowName(const std::string &windowName)
    {
        backWindowName = windowName;
    };
};

class WeekDaysRepeatData : public gui::SwitchData
{
  protected:
    bool weekDays[style::window::calendar::week_days_number];

  public:
    WeekDaysRepeatData();
    virtual ~WeekDaysRepeatData() = default;
    [[nodiscard]] auto getData(const uint32_t &weekDay) const -> bool;
    virtual void setData(const uint32_t &weekDay);
};

class DayMonthData : public gui::SwitchData
{
  protected:
    std::string dayMonth;
    TimePoint dateFilter;

  public:
    DayMonthData()          = default;
    virtual ~DayMonthData() = default;
    std::string getDayMonthText()
    {
        return dayMonth;
    };

    TimePoint getDateFilter()
    {
        return dateFilter;
    };

    virtual void setData(std::string dayMonthText, const TimePoint &dateNumb)
    {
        dayMonth   = dayMonthText;
        dateFilter = dateNumb;
    };
};

class PrevWindowData : public gui::SwitchData
{
  public:
    enum PrevWindow
    {
        Delete = 0,
        Edit,
        Add
    };

  protected:
    PrevWindow prevWindow;

  public:
    PrevWindowData()          = default;
    virtual ~PrevWindowData() = default;

    PrevWindow getData()
    {
        return prevWindow;
    };

    virtual void setData(PrevWindow data)
    {
        prevWindow = data;
    };
};

A module-apps/application-calendar/data/OptionParser.hpp => module-apps/application-calendar/data/OptionParser.hpp +52 -0
@@ 0,0 1,52 @@
#pragma once

#include "CalendarData.hpp"

class OptionParser
{
  private:
    constexpr static const int start_bit   = 16;
    constexpr static const int options_num = 7;

  public:
    OptionParser() = default;
    std::unique_ptr<WeekDaysRepeatData> setWeekDayOptions(const uint32_t &dataDB,
                                                          std::unique_ptr<WeekDaysRepeatData> weekDayOptions)
    {
        const uint32_t startBit        = start_bit;
        const uint32_t numberOfOptions = options_num;
        for (uint32_t i = startBit; i < startBit + numberOfOptions; i++) {
            if (dataDB & (1 << i)) {
                weekDayOptions->setData(i - startBit);
            }
        }
        return weekDayOptions;
    }

    uint32_t getDatabaseFieldValue(std::unique_ptr<WeekDaysRepeatData> weekDayOptions)
    {
        uint32_t dataDB                = 0;
        const uint32_t startBit        = start_bit;
        const uint32_t numberOfOptions = options_num;
        for (uint32_t i = startBit; i < startBit + numberOfOptions; i++) {
            if (weekDayOptions->getData(i - startBit)) {
                dataDB += (1 << i);
            }
        }
        return dataDB;
    }

    uint32_t getNoCustomValue(uint32_t dataDB)
    {
        /// Set all bits in custom field to zero
        /// DataDB input is not modifyed
        const uint32_t startBit        = start_bit;
        const uint32_t numberOfOptions = options_num;
        for (uint32_t i = startBit; i < startBit + numberOfOptions; i++) {
            if (dataDB & (1 << i)) {
                dataDB -= (1 << i);
            }
        }
        return dataDB;
    }
};

A module-apps/application-calendar/data/TimeDisplayParser.hpp => module-apps/application-calendar/data/TimeDisplayParser.hpp +89 -0
@@ 0,0 1,89 @@
#pragma once
#include "module-apps/application-calendar/widgets/CalendarStyle.hpp"
#include <Utils.hpp>
#include <module-db/Interface/EventsRecord.hpp>
#include <time/time_locale.hpp>

class TimeDisplayParser
{

  private:
    std::string getAMorPM(bool is_am)
    {
        if (is_am) {
            return utils::localize.get(utils::time::Locale::getAM());
        }
        else {
            return utils::localize.get(utils::time::Locale::getPM());
        }
    }

  public:
    TimeDisplayParser() = default;

    std::string getTimeString(const std::shared_ptr<EventsRecord> &event,
                              bool isShortVersion = false,
                              bool isMode24H      = false)
    {
        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() == style::window::calendar::time::max_hour_24H_mode &&
            end_time.minutes().count() == style::window::calendar::time::max_minutes) {
            return utils::localize.get("app_calendar_all_day");
        }
        else {
            bool start_is_am = true;
            bool end_is_am   = true;
            auto start_h     = std::to_string(start_time.hours().count());
            auto start_min   = std::to_string(start_time.minutes().count());
            auto end_h       = std::to_string(end_time.hours().count());
            auto end_min     = std::to_string(end_time.minutes().count());

            if (start_min.length() < style::window::calendar::time::max_time_length) {
                start_min.insert(0, style::window::calendar::time::max_time_length / 2, '0');
            }
            if (end_min.length() < style::window::calendar::time::max_time_length) {
                end_min.insert(0, style::window::calendar::time::max_time_length / 2, '0');
            }

            if (!isMode24H) {
                start_is_am = date::is_am(start_time.hours());
                end_is_am   = date::is_am(end_time.hours());
                start_h     = std::to_string(date::make12(start_time.hours()).count());
                end_h       = std::to_string(date::make12(end_time.hours()).count());
            }

            if (start_h.length() < style::window::calendar::time::max_time_length) {
                start_h.insert(0, style::window::calendar::time::max_time_length / 2, '0');
            }
            if (end_h.length() < style::window::calendar::time::max_time_length) {
                end_h.insert(0, style::window::calendar::time::max_time_length / 2, '0');
            }

            if (isShortVersion) {
                if (!isMode24H) {
                    return start_h + ":" + start_min + " " + getAMorPM(start_is_am);
                }
                else {
                    return start_h + ":" + start_min;
                }
            }
            else {
                if (!isMode24H) {
                    if (start_is_am != end_is_am) {
                        return start_h + ":" + start_min + " " + getAMorPM(start_is_am) + " - " + end_h + ":" +
                               end_min + " " + getAMorPM(end_is_am);
                    }
                    else {
                        return start_h + ":" + start_min + " - " + end_h + ":" + end_min + " " + getAMorPM(start_is_am);
                    }
                }
                else {
                    return start_h + ":" + start_min + " - " + end_h + ":" + end_min;
                }
            }
        }
    }
};

A module-apps/application-calendar/data/dateCommon.hpp => module-apps/application-calendar/data/dateCommon.hpp +166 -0
@@ 0,0 1,166 @@
#ifndef DATECOMMON_H
#define DATECOMMON_H

#include <module-utils/date/include/date/date.h>
#include <time/time_conversion.hpp>

using namespace std::chrono;

using Clock            = system_clock;
using TimePoint        = time_point<Clock>;
using YearMonthDay     = date::year_month_day;
using YearMonthDayLast = date::year_month_day_last;

const inline int max_month_day = 48;

enum class Reminder
{
    never,
    event_time,
    five_min_before,
    fifteen_min_before,
    thirty_min_before,
    one_hour_before,
    two_hour_before,
    one_day_before,
    two_days_before,
    one_week_before
};

enum class Repeat
{
    never,
    daily,
    weekly,
    two_weeks,
    month,
    year,
    custom
};

constexpr TimePoint TIME_POINT_INVALID = TimePoint::min();

inline std::tm CreateTmStruct(int year, int month, int day, int hour, int minutes, int seconds)
{
    struct tm tm_ret;

    tm_ret.tm_isdst = -1;
    tm_ret.tm_sec   = seconds;
    tm_ret.tm_min   = minutes;
    tm_ret.tm_hour  = hour;
    tm_ret.tm_mday  = day;
    tm_ret.tm_mon   = month - 1;
    tm_ret.tm_year  = year - 1900;

    return tm_ret;
}

inline time_t GetDiffLocalWithUTCTime()
{
    std::tm tm = CreateTmStruct(2000, 1, 1, 0, 0, 0);

    std::time_t basetime = std::mktime(&tm);
    std::time_t diff;

    tm          = *std::localtime(&basetime);
    tm.tm_isdst = -1;
    diff        = std::mktime(&tm);

    tm          = *std::gmtime(&basetime);
    tm.tm_isdst = -1;
    diff -= std::mktime(&tm);

    return diff;
}

inline time_t GetAsUTCTime(int year, int month, int day, int hour = 0, int minutes = 0, int seconds = 0)
{
    std::tm tm           = CreateTmStruct(year, month, day, hour, minutes, seconds);
    std::time_t basetime = std::mktime(&tm);

    return basetime + GetDiffLocalWithUTCTime();
}

inline TimePoint TimePointFromTimeT(const time_t &time)
{
    return system_clock::from_time_t(time);
}

inline TimePoint TimePointNow()
{
    utils::time::Timestamp timestamp;
    return TimePointFromTimeT(timestamp.getTime());
}

inline std::string TimePointToString(const TimePoint &tp)
{
    return date::format("%F %T", 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)};
    date::year_month_day yearMonthDayLast = yearMonthDay.year() / yearMonthDay.month() / date::last;

    TimePoint timePoint;

    if ((static_cast<unsigned>(yearMonthDay.month()) + months.count()) <= 12) {
        if (yearMonthDayLast.day() == yearMonthDay.day()) {
            yearMonthDayLast = yearMonthDay.year() / (yearMonthDay.month() + months) / date::last;
            timePoint = date::sys_days{yearMonthDayLast.year() / yearMonthDayLast.month() / yearMonthDayLast.day()};
        }
        else {
            timePoint = date::sys_days{yearMonthDay.year() / (yearMonthDay.month() + months) / yearMonthDay.day()};
        }
    }
    else {
        date::month incrementedMonths = date::month(months.count()) - (date::month(12) - yearMonthDay.month());
        yearMonthDay                  = (yearMonthDay.year() + date::years{1}) / incrementedMonths / yearMonthDay.day();
        if (yearMonthDayLast.day() == yearMonthDay.day()) {
            yearMonthDayLast = yearMonthDay.year() / incrementedMonths / date::last;
            timePoint = date::sys_days{yearMonthDayLast.year() / yearMonthDayLast.month() / yearMonthDayLast.day()};
        }
        else {
            timePoint = date::sys_days{yearMonthDay.year() / yearMonthDay.month() / yearMonthDay.day()};
        }
    }
    return date::format("%F %T", time_point_cast<seconds>(timePoint));
}

inline TimePoint TimePointFromString(const char *s1)
{
    TimePoint tp;
    std::istringstream(s1) >> date::parse("%F %T", tp);
    return tp;
}

inline time_t TimePointToTimeT(const TimePoint &tp)
{
    return system_clock::to_time_t(tp);
}

inline YearMonthDay TimePointToYearMonthDay(const TimePoint &tp)
{
    return date::year_month_day{date::floor<date::days>(tp)};
}

inline TimePoint TimePointFromYearMonthDay(const YearMonthDay &ymd)
{
    return date::sys_days{ymd.year() / ymd.month() / ymd.day()};
}

inline auto TimePointToHourMinSec(const TimePoint &tp)
{
    auto dp = date::floor<date::days>(tp);
    return date::make_time(tp - dp);
}

// 0: Monday, 1: Tuesday ... 6: Sunday
inline unsigned int WeekdayIndexFromTimePoint(const TimePoint &tp)
{
    auto ymw = date::year_month_weekday{floor<date::days>(tp)};
    return ymw.weekday().iso_encoding() - 1;
}

#endif
// DATECOMMON_H

M module-apps/application-calendar/models/AllEventsModel.cpp => module-apps/application-calendar/models/AllEventsModel.cpp +33 -4
@@ 1,17 1,26 @@
#include "AllEventsModel.hpp"
#include "application-calendar/widgets/AllEventsItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include <ListView.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <queries/calendar/QueryEventsGetAllLimited.hpp>

AllEventsModel::AllEventsModel(app::Application *app)
AllEventsModel::AllEventsModel(app::Application *app) : DatabaseModel(app)
{
    application = app;
    assert(app != nullptr);
}

unsigned int AllEventsModel::requestRecordsCount()
{
    return recordsCount;
}

void AllEventsModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    list->onProviderDataUpdate();
    auto query = std::make_unique<db::query::events::GetAllLimited>(offset, limit);
    DBServiceAPI::GetQuery(application, db::Interface::Name::Events, std::move(query));
}

unsigned int AllEventsModel::getMinimalItemHeight() const


@@ 21,13 30,33 @@ unsigned int AllEventsModel::getMinimalItemHeight() const

gui::ListItem *AllEventsModel::getItem(gui::Order order)
{
    auto *item = new gui::AllEventsItem();
    auto record = getRecord(order);
    if (record == nullptr) {
        LOG_DEBUG("Empty record in AllEventsModel::GetItem");
        return nullptr;
    }

    auto *item = new gui::AllEventsItem();
    item->setEvent(record);
    item->activatedCallback = [=](gui::Item &item) {
        LOG_INFO("Switch to event details window");
        application->switchWindow(style::window::calendar::name::details_window);
        auto rec  = std::make_unique<EventsRecord>(*record);
        auto data = std::make_unique<EventRecordData>(std::move(rec));
        data->setWindowName(style::window::calendar::name::all_events_window);
        application->switchWindow(style::window::calendar::name::details_window, std::move(data));
        return true;
    };

    return item;
}

bool AllEventsModel::updateRecords(std::unique_ptr<std::vector<EventsRecord>> records)
{
    DatabaseModel::updateRecords(std::move(records));
    list->onProviderDataUpdate();
    return true;
}
void AllEventsModel::setRecordsCount(const uint32_t count)
{
    list->setElementsCount(count);
}

M module-apps/application-calendar/models/AllEventsModel.hpp => module-apps/application-calendar/models/AllEventsModel.hpp +6 -6
@@ 2,23 2,23 @@

#include "Application.hpp"
#include <ListItemProvider.hpp>
#include <DatabaseModel.hpp>
#include <module-db/Interface/EventsRecord.hpp>

class AllEventsModel : public gui::ListItemProvider
class AllEventsModel : public app::DatabaseModel<EventsRecord>, public gui::ListItemProvider
{
    static const int tempItemCount = 10;
    app::Application *application  = nullptr;

  public:
    AllEventsModel(app::Application *app);
    virtual ~AllEventsModel() override = default;

    void setRecordsCount(const uint32_t count);
    void requestRecords(const uint32_t offset, const uint32_t limit) override;
    bool updateRecords(std::unique_ptr<std::vector<EventsRecord>> records) override;

    // virtual methods for ListViewProvider
    [[nodiscard]] unsigned int getMinimalItemHeight() const override;
    gui::ListItem *getItem(gui::Order order) override;
    [[nodiscard]] unsigned int requestRecordsCount() override
    {
        return tempItemCount;
    };
    [[nodiscard]] unsigned int requestRecordsCount() override;
};

D module-apps/application-calendar/models/CalendarEventsModel.cpp => module-apps/application-calendar/models/CalendarEventsModel.cpp +0 -57
@@ 1,57 0,0 @@

#include "CalendarEventsModel.hpp"
#include "application-calendar/widgets/CalendarItem.hpp"

#include <ListView.hpp>

CalendarEventsModel::CalendarEventsModel(app::Application *app) : DatabaseModel(app)
{
    application = app;
}

void CalendarEventsModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    list->onProviderDataUpdate();
}

unsigned int CalendarEventsModel::getMinimalItemHeight() const
{
    return style::window::calendar::item::height;
}

gui::ListItem *CalendarEventsModel::getItem(gui::Order order)
{
    gui::CalendarItem *item = new gui::CalendarItem();

    auto record = getRecord(order);
    if (record != nullptr) {
        item->setEvent(record);
    }
    else {
        LOG_DEBUG("Empty record in EventsModel::GetItem");
        return nullptr;
    }
    LOG_DEBUG("Created new item in calendar day listView");
    item->activatedCallback = [=](gui::Item &item) {
        LOG_INFO("Switch to options/delete window");
        application->switchWindow(style::window::calendar::name::events_options);
        return true;
    };
    return item;
}
bool CalendarEventsModel::updateRecords(std::unique_ptr<std::vector<EventsRecord>> records,
                                        uint32_t offset,
                                        uint32_t limit,
                                        uint32_t count)
{
    DatabaseModel::updateRecords(std::move(records), offset, limit, count);
    modelIndex = 0;
    list->onProviderDataUpdate();

    return true;
}

void CalendarEventsModel::setRecordsCount(const uint32_t &count)
{
    recordsCount = count;
}

M module-apps/application-calendar/models/CustomRepeatModel.cpp => module-apps/application-calendar/models/CustomRepeatModel.cpp +10 -16
@@ 27,40 27,34 @@ gui::ListItem *CustomRepeatModel::getItem(gui::Order order)
    return getRecord(order);
}

void CustomRepeatModel::createData()
void CustomRepeatModel::createData(const std::shared_ptr<WeekDaysRepeatData> &data)
{
    internalData.push_back(
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Monday)));
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Monday), data));
    internalData.push_back(
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Tuesday)));
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Tuesday), data));
    internalData.push_back(
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Wednesday)));
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Wednesday), data));
    internalData.push_back(
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Thursday)));
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Thursday), data));
    internalData.push_back(
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Friday)));
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Friday), data));
    internalData.push_back(
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Saturday)));
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Saturday), data));
    internalData.push_back(
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Sunday)));
        new gui::CheckBoxWithLabelItem(application, utils::localize.get(style::strings::common::Sunday), data));

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

void CustomRepeatModel::loadData()
void CustomRepeatModel::loadData(const std::shared_ptr<WeekDaysRepeatData> &data)
{
    list->clear();
    eraseInternalData();

    createData();

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

    list->rebuildList();
}

M module-apps/application-calendar/models/CustomRepeatModel.hpp => module-apps/application-calendar/models/CustomRepeatModel.hpp +8 -2
@@ 2,6 2,7 @@
#include "Application.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/widgets/CalendarListItem.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include "InternalModel.hpp"
#include <ListItemProvider.hpp>



@@ 12,13 13,18 @@ class CustomRepeatModel : public app::InternalModel<gui::CalendarListItem *>, pu
  public:
    CustomRepeatModel(app::Application *app);

    void loadData();
    void loadData(const std::shared_ptr<WeekDaysRepeatData> &data);

    [[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;

    std::vector<gui::CalendarListItem *> getInternalData()
    {
        return internalData;
    }

  private:
    void createData();
    void createData(const std::shared_ptr<WeekDaysRepeatData> &data);
};

A module-apps/application-calendar/models/DayEventsInternalModel.cpp => module-apps/application-calendar/models/DayEventsInternalModel.cpp +61 -0
@@ 0,0 1,61 @@
#include "DayEventsInternalModel.hpp"
#include "application-calendar/widgets/DayEventsItem.hpp"
#include "application-calendar/data/CalendarData.hpp"
#include <ListView.hpp>
#include <algorithm>

DayEventsInternalModel::DayEventsInternalModel(app::Application *app) : application(app)
{}

unsigned int DayEventsInternalModel::requestRecordsCount()
{
    return internalData.size();
}

unsigned int DayEventsInternalModel::getMinimalItemHeight() const
{
    return style::window::calendar::item::dayEvents::height;
}

void DayEventsInternalModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    setupModel(offset, limit);
    list->onProviderDataUpdate();
}

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

void DayEventsInternalModel::loadData(std::unique_ptr<std::vector<EventsRecord>> records)
{
    auto app = application;
    assert(app != nullptr);

    list->clear();
    eraseInternalData();

    std::sort(records->begin(), records->end(), [](const EventsRecord &first, const EventsRecord &second) {
        return first.date_from < second.date_from;
    });

    for (auto &record : *records) {
        auto item = new gui::DayEventsItem();
        item->setEvent(std::make_shared<EventsRecord>(record));
        item->activatedCallback = [=](gui::Item &item) {
            auto rec  = std::make_unique<EventsRecord>(record);
            auto data = std::make_unique<EventRecordData>(std::move(rec));
            data->setWindowName(style::window::calendar::name::day_events_window);
            app->switchWindow(style::window::calendar::name::details_window, std::move(data));
            return true;
        };
        internalData.push_back(item);
    }

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

    list->rebuildList();
}

R module-apps/application-calendar/models/DayEventsModel.hpp => module-apps/application-calendar/models/DayEventsInternalModel.hpp +8 -14
@@ 1,28 1,22 @@
#pragma once

#include "application-calendar/widgets/CalendarStyle.hpp"
#include "Application.hpp"
#include "DatabaseModel.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "InternalModel.hpp"
#include <ListItem.hpp>
#include <ListItemProvider.hpp>
#include <module-db/Interface/EventsRecord.hpp>

class DayEventsModel : public app::DatabaseModel<EventsRecord>, public gui::ListItemProvider
class DayEventsInternalModel : public app::InternalModel<gui::ListItem *>, public gui::ListItemProvider
{
    app::Application *application = nullptr;

  public:
    DayEventsModel(app::Application *app);
    virtual ~DayEventsModel() override = default;
    auto updateRecords(std::unique_ptr<std::vector<EventsRecord>> records) -> bool override;
    DayEventsInternalModel(app::Application *app);

    void requestRecords(const uint32_t offset, const uint32_t limit) override;
    void setRecordsCount(const uint32_t &count);
    void loadData(std::unique_ptr<std::vector<EventsRecord>> records);

    // virtual methods for ListViewProvider
    [[nodiscard]] unsigned int getMinimalItemHeight() const override;
    [[nodiscard]] unsigned int requestRecordsCount() override;
    gui::ListItem *getItem(gui::Order order) override;
    [[nodiscard]] unsigned int requestRecordsCount() override
    {
        return recordsCount;
    }
    void requestRecords(const uint32_t offset, const uint32_t limit) override;
};

D module-apps/application-calendar/models/DayEventsModel.cpp => module-apps/application-calendar/models/DayEventsModel.cpp +0 -54
@@ 1,54 0,0 @@
#include "DayEventsModel.hpp"
#include "application-calendar/widgets/DayEventsItem.hpp"
#include <ListView.hpp>

DayEventsModel::DayEventsModel(app::Application *app) : DatabaseModel(app)
{
    application = app;
    assert(app != nullptr);
}

void DayEventsModel::requestRecords(const uint32_t offset, const uint32_t limit)
{
    list->onProviderDataUpdate();
}

unsigned int DayEventsModel::getMinimalItemHeight() const
{
    return style::window::calendar::item::dayEvents::height;
}

gui::ListItem *DayEventsModel::getItem(gui::Order order)
{
    auto item = new gui::DayEventsItem();

    auto record = getRecord(order);
    if (record != nullptr) {
        item->setEvent(record);
    }
    else {
        LOG_DEBUG("Empty record in EventsModel::GetItem");
        return nullptr;
    }
    LOG_DEBUG("Created new item in calendar day listView");
    item->activatedCallback = [=](gui::Item &item) {
        LOG_INFO("Switch to options/delete window");
        application->switchWindow(style::window::calendar::name::events_options);
        return true;
    };
    return item;
}

bool DayEventsModel::updateRecords(std::unique_ptr<std::vector<EventsRecord>> records)
{
    DatabaseModel::updateRecords(std::move(records));
    modelIndex = 0;
    list->onProviderDataUpdate();

    return true;
}

void DayEventsModel::setRecordsCount(const uint32_t &count)
{
    recordsCount = count;
}

M module-apps/application-calendar/models/EventDetailModel.cpp => module-apps/application-calendar/models/EventDetailModel.cpp +6 -3
@@ 29,15 29,18 @@ gui::ListItem *EventDetailModel::getItem(gui::Order order)

void EventDetailModel::createData()
{
    auto app = dynamic_cast<app::ApplicationCalendar *>(application);
    assert(app != nullptr);

    internalData.push_back(new gui::EventDetailDescriptionItem());
    internalData.push_back(new gui::RepeatAndReminderItem());
    internalData.push_back(new gui::RepeatAndReminderItem(app));

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

void EventDetailModel::loadData()
void EventDetailModel::loadData(std::shared_ptr<EventsRecord> record)
{
    list->clear();
    eraseInternalData();


@@ 46,7 49,7 @@ void EventDetailModel::loadData()

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


M module-apps/application-calendar/models/EventDetailModel.hpp => module-apps/application-calendar/models/EventDetailModel.hpp +2 -1
@@ 2,6 2,7 @@

#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/widgets/CalendarListItem.hpp"
#include "module-apps/application-calendar/ApplicationCalendar.hpp"
#include "Application.hpp"
#include "InternalModel.hpp"
#include <ListItemProvider.hpp>


@@ 13,7 14,7 @@ class EventDetailModel : public app::InternalModel<gui::CalendarListItem *>, pub
  public:
    EventDetailModel(app::Application *app);

    void loadData();
    void loadData(std::shared_ptr<EventsRecord> record);

    [[nodiscard]] auto requestRecordsCount() -> unsigned int override;
    [[nodiscard]] unsigned int getMinimalItemHeight() const override;

M module-apps/application-calendar/models/MonthModel.cpp => module-apps/application-calendar/models/MonthModel.cpp +24 -1
@@ 11,9 11,14 @@ MonthModel::MonthModel(date::year_month_day yearMonthDay)
    this->firstWeekDayNumb                     = date::weekday{yearMonthDayFirst}.c_encoding();
}

date::year MonthModel::getYear()
{
    return year;
}

date::month MonthModel::getMonth()
{
    return this->month;
    return month;
}

uint32_t MonthModel::getLastDay()


@@ 31,6 36,24 @@ uint32_t MonthModel::getFirstWeekOffset()
    }
}

std::vector<std::string> MonthModel::split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::string MonthModel::getMonthText()
{
    unsigned int monthUInt = static_cast<unsigned>(month);
    std::string monthStr   = utils::time::Locale::get_month(utils::time::Locale::Month(monthUInt - 1));
    return monthStr;
}

std::string MonthModel::getMonthYearText()
{
    int yearUInt        = static_cast<decltype(yearUInt)>(year);

M module-apps/application-calendar/models/MonthModel.hpp => module-apps/application-calendar/models/MonthModel.hpp +3 -0
@@ 9,6 9,7 @@
#include <map>
#include <string>
#include <vector>
#include <module-apps/application-calendar/data/dateCommon.hpp>

class MonthModel
{


@@ 29,4 30,6 @@ class MonthModel
    uint32_t getLastDay();
    uint32_t getFirstWeekOffset();
    std::string getMonthYearText();
    std::string getMonthText();
    std::vector<std::string> split(const std::string &s, char delim);
};

M module-apps/application-calendar/models/NewEditEventModel.cpp => module-apps/application-calendar/models/NewEditEventModel.cpp +86 -11
@@ 1,8 1,12 @@
#include "NewEditEventModel.hpp"
#include "application-calendar/widgets/CheckBoxWithLabelAndModel.hpp"
#include "application-calendar/widgets/NewEventCheckBoxWithLabel.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include <ListView.hpp>
#include <Utils.hpp>
#include <BottomBar.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <module-db/queries/calendar/QueryEventsAdd.hpp>
#include <module-db/queries/calendar/QueryEventsEdit.hpp>
#include <time/time_conversion.hpp>

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


@@ 23,6 27,27 @@ 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);


@@ 39,7 64,7 @@ void NewEditEventModel::createData(bool allDayEvent)
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
        [app]() { app->getCurrentWindow()->selectSpecialCharacter(); });

    allDayEventCheckBox = new gui::CheckBoxWithLabelAndModel(
    allDayEventCheckBox = new gui::NewEventCheckBoxWithLabel(
        application, utils::localize.get("app_calendar_new_edit_event_allday"), true, this);

    startTime = new gui::EventTimeItem(


@@ 66,6 91,9 @@ void NewEditEventModel::createData(bool allDayEvent)
        [app](const UTF8 &text) { app->getCurrentWindow()->bottomBarTemporaryMode(text, false); },
        [app]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); });

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

    internalData.push_back(eventNameInput);
    internalData.push_back(allDayEventCheckBox);
    if (!allDayEvent) {


@@ 80,22 108,36 @@ void NewEditEventModel::createData(bool allDayEvent)
    }
}

void NewEditEventModel::loadData(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() == style::window::calendar::time::max_hour_24H_mode &&
               end_time.minutes().count() == style::window::calendar::time::max_minutes;
    };

    createData(allDayEvent);
    createData(isAllDayEvent());

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

    list->rebuildList();
}

void NewEditEventModel::loadRepeat(const std::shared_ptr<EventsRecord> &record)
{
    if (repeat->onLoadCallback) {
        repeat->onLoadCallback(record);
    }
}

void NewEditEventModel::loadDataWithoutTimeItem()
{
    internalData.erase(std::find(internalData.begin(), internalData.end(), startTime));


@@ 105,9 147,6 @@ void NewEditEventModel::loadDataWithoutTimeItem()

void NewEditEventModel::reloadDataWithTimeItem()
{
    [[maybe_unused]] auto app = application;
    assert(app != nullptr);

    internalData.clear();

    internalData.push_back(eventNameInput);


@@ 124,11 163,47 @@ void NewEditEventModel::reloadDataWithTimeItem()
    list->rebuildList();
}

void NewEditEventModel::saveData()
void NewEditEventModel::saveData(std::shared_ptr<EventsRecord> event, bool edit, const std::string &windowName)
{
    for (auto &item : internalData) {
        if (item->onSaveCallback) {
            item->onSaveCallback();
            item->onSaveCallback(event);
        }
    }

    if (edit) {
        auto record = event.get();
        if (record->title != "") {
            DBServiceAPI::GetQuery(
                application, db::Interface::Name::Events, std::make_unique<db::query::events::Edit>(*record));
        }
        application->switchWindow(windowName);
    }
    else {
        auto record = event.get();
        if (record->title != "") {
            DBServiceAPI::GetQuery(
                application, db::Interface::Name::Events, std::make_unique<db::query::events::Add>(*record));

            if (application->getPrevWindow() == style::window::calendar::name::no_events_window) {
                auto data      = std::make_unique<DayMonthData>();
                auto startDate = TimePointToYearMonthDay(record->date_from);
                std::string monthStr =
                    utils::time::Locale::get_month(utils::time::Locale::Month(unsigned(startDate.month()) - 1));
                data->setData(std::to_string(unsigned(startDate.day())) + " " + monthStr, record->date_from);

                application->switchWindow(gui::name::window::main_window);
                application->switchWindow(windowName, std::move(data));
            }
            else {
                application->returnToPreviousWindow();
            }
        }
        else {
            application->returnToPreviousWindow();
        }
    }

    list->clear();
    eraseInternalData();
}

M module-apps/application-calendar/models/NewEditEventModel.hpp => module-apps/application-calendar/models/NewEditEventModel.hpp +7 -2
@@ 24,16 24,21 @@ class NewEditEventModel : public app::InternalModel<gui::CalendarListItem *>, pu
  public:
    NewEditEventModel(app::Application *app, bool mode24H = false);

    void loadData(bool allDayEvent);
    void loadData(std::shared_ptr<EventsRecord> record);
    void loadRepeat(const std::shared_ptr<EventsRecord> &record);
    void loadDataWithoutTimeItem();
    void reloadDataWithTimeItem();
    void saveData();
    void saveData(std::shared_ptr<EventsRecord> event, bool edit, const std::string &windowName);
    void addReapetedRecords(std::shared_ptr<EventsRecord> event);

    [[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/AllEventsItem.cpp => module-apps/application-calendar/widgets/AllEventsItem.cpp +18 -4
@@ 1,14 1,18 @@
#include "AllEventsItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/data/TimeDisplayParser.hpp"
#include "CalendarListItem.hpp"
#include <Style.hpp>
#include <gui/widgets/Label.hpp>
#include <time/time_conversion.hpp>
#include <module-utils/date/include/date/date.h>

namespace gui
{
    AllEventsItem::AllEventsItem()
    {
        setMinimumSize(style::window::default_body_width, style::window::label::big_h);
        setMargins(gui::Margins(0, style::margins::big, 0, 0));

        hBox = new gui::HBox(this, 0, 0, 0, 0);
        hBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);


@@ 20,6 24,7 @@ namespace gui
        startTime->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        startTime->setFont(style::window::font::small);
        startTime->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});
        startTime->setMargins(gui::Margins(style::margins::small, 0, 0, 0));

        description = new gui::Label(hBox, 0, 0, 0, 0);
        description->setMinimumSize(style::window::calendar::item::allEvents::description_w,


@@ 27,9 32,6 @@ namespace gui
        description->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        description->setFont(style::window::font::bigbold);
        description->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});

        description->setText(utils::localize.get("common_information"));
        startTime->setText(utils::time::DateTime().str());
    }

    bool AllEventsItem::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim)


@@ 51,7 53,19 @@ namespace gui

    UTF8 AllEventsItem::getLabelMarker() const
    {
        return utils::time::Time().str("%d %B");
        auto startDate = TimePointToYearMonthDay(record->date_from);

        std::string monthStr =
            utils::time::Locale::get_month(utils::time::Locale::Month(unsigned(startDate.month()) - 1));
        return std::to_string(unsigned(startDate.day())) + " " + monthStr;
    }

    void AllEventsItem::setEvent(std::shared_ptr<EventsRecord> rec)
    {
        this->record = rec;
        if (rec != nullptr) {
            description->setText(this->record->title.c_str());
            startTime->setText(TimeDisplayParser().getTimeString(record, true));
        }
    }
} /* namespace gui */

M module-apps/application-calendar/widgets/AllEventsItem.hpp => module-apps/application-calendar/widgets/AllEventsItem.hpp +3 -0
@@ 2,6 2,7 @@
#include <ListItem.hpp>
#include <Label.hpp>
#include <BoxLayout.hpp>
#include <module-db/Interface/EventsRecord.hpp>

namespace gui
{


@@ 10,6 11,7 @@ namespace gui
        gui::HBox *hBox         = nullptr;
        gui::Label *startTime   = nullptr;
        gui::Label *description = nullptr;
        std::shared_ptr<EventsRecord> record;

      public:
        AllEventsItem();


@@ 17,6 19,7 @@ namespace gui

        void setMarkerItem(UTF8 text);
        [[nodiscard]] UTF8 getLabelMarker() const;
        void setEvent(std::shared_ptr<EventsRecord> record);

        // virtual methods from Item
        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;

M module-apps/application-calendar/widgets/CalendarListItem.hpp => module-apps/application-calendar/widgets/CalendarListItem.hpp +3 -2
@@ 1,4 1,5 @@
#pragma once
#include <module-db/Interface/EventsRecord.hpp>
#include <ListItem.hpp>

namespace gui


@@ 6,8 7,8 @@ namespace gui
    class CalendarListItem : public ListItem
    {
      public:
        std::function<void()> onSaveCallback = nullptr;
        std::function<void()> onLoadCallback = nullptr;
        std::function<void(std::shared_ptr<EventsRecord> event)> onSaveCallback = nullptr;
        std::function<void(std::shared_ptr<EventsRecord> event)> onLoadCallback = nullptr;
    };

} /* namespace gui */

M module-apps/application-calendar/widgets/CalendarStyle.hpp => module-apps/application-calendar/widgets/CalendarStyle.hpp +32 -40
@@ 21,6 21,8 @@ namespace style
                const inline std::string custom_repeat_window = "CustomRepeat";
            } // namespace name

            const inline std::string new_event  = "New";
            const inline std::string edit_event = "Edit";
            const inline int day_cell_width    = 60;
            const inline int day_cell_height   = 55;
            const inline int month_year_height = 60;


@@ 31,10 33,10 @@ namespace style
            const inline int cross_y    = 55;
            const inline int arrow_x    = 30;
            const inline int arrow_y    = 62;
            const inline int listView_x = 16;
            const inline int listView_y = 110;
            const inline int listView_w = 448;
            const inline int listView_h = 440;
            const inline int listView_x = style::window::default_left_margin;
            const inline int listView_y = style::header::height;
            const inline int listView_w = style::listview::body_width_with_scroll;
            const inline int listView_h = style::window_height - listView_y - style::footer::height;

            namespace test
            {


@@ 46,15 48,21 @@ namespace style
                const inline std::string date_text_3 = "March 2019";
            } // namespace test

            namespace time
            {
                const inline int max_time_length   = 2;
                const inline int max_hour_24H_mode = 23;
                const inline int max_hour_12H_mode = 12;
                const inline int max_minutes       = 59;
            } // namespace time

            namespace item
            {
                namespace dayEvents
                {
                    const inline int title_w       = 200;
                    const inline int h_box_h       = 40;
                    const inline int description_h = 30;
                    const inline int margins       = 10;
                    const inline int height        = 90;
                    const inline int title_w    = 255;
                    const inline int box_height = style::window::label::small_h;
                    const inline int height     = 100;
                } // namespace dayEvents

                namespace allEvents


@@ 75,56 83,40 @@ namespace style
                namespace eventDetail
                {
                    const inline int height_min    = 90;
                    const inline int height_max    = 160;
                    const inline int margin_top    = 25;
                    const inline int margin_bottom = 10;
                    const inline int height_max        = 155;
                    const inline int margin_top        = 2 * style::margins::big;
                    const inline int event_time_margin = 25;
                    const inline int title_h       = 20;
                    const inline int event_time_h  = 30;
                    const inline int description_h = 40;
                    const inline int label_h           = 35;
                } // namespace eventDetail

                namespace eventTime
                {
                    const inline int height               = 120;
                    const inline int margin               = 22;
                    const inline int description_label_w  = 150;
                    const inline int description_label_h  = 30;
                    const inline int colon_label_w        = 25;
                    const inline int colon_label_h        = 20;
                    const inline int time_input_12h_w     = 125;
                    const inline int time_input_24h_w     = 202;
                    const inline int mode12h_input_margin = 25;
                    const inline int height           = 106;
                    const inline int margin           = 21;
                    const inline int separator        = 30;
                    const inline int time_input_12h_w = 120;
                    const inline int time_input_24h_w = 195;
                } // namespace eventTime

                namespace checkBox
                {
                    const inline int height              = 52;
                    const inline int margin_top          = 6;
                    const inline int margin_bottom       = 5;
                    const inline int input_box_label_w   = 55;
                    const inline int input_box_label_h   = 50;
                    const inline int height              = 44;
                    const inline int margin_top          = 18;
                    const inline int input_box_label_w   = style::window::label::big_h;
                    const inline int description_label_w = 280;
                    const inline int description_label_h = 40;
                    const inline int description_margin  = 20;
                    const inline int tick_image_w        = 30;
                    const inline int tick_image_h        = 30;
                } // namespace checkBox

                namespace severalOptions
                {
                    const inline int height              = 62;
                    const inline int margin              = 15;
                    const inline int description_label_w = 100;
                    const inline int description_label_h = 30;
                    const inline int option_label_h      = 30;
                    const inline int arrow_w             = 20;
                    const inline int arrow_h             = 20;
                    const inline int height    = 63;
                    const inline int label_h   = 30;
                    const inline int arrow_w_h = 20;
                } // namespace severalOptions

                namespace textWithLabel
                {
                    const inline int height        = 80;
                    const inline int margin        = 5;
                    const inline int description_h = 30;
                    const inline int text_input_h  = 40;
                } // namespace textWithLabel

M module-apps/application-calendar/widgets/CheckBoxWithLabelItem.cpp => module-apps/application-calendar/widgets/CheckBoxWithLabelItem.cpp +34 -12
@@ 1,27 1,24 @@
#include "CheckBoxWithLabelItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/windows/NewEditEventWindow.hpp"
#include "windows/AppWindow.hpp"
#include <ListView.hpp>
#include <Style.hpp>
#include <time/time_conversion.hpp>
#include <Utils.hpp>

namespace gui
{

    CheckBoxWithLabelItem::CheckBoxWithLabelItem(app::Application *application,
                                                 const std::string &description,
                                                 std::shared_ptr<WeekDaysRepeatData> data,
                                                 bool checkIsOnLeftBarSide)
        : app(application), checkIsOnLeftBarSide(checkIsOnLeftBarSide)
        : app(application), checkBoxData(std::move(data)), checkIsOnLeftBarSide(checkIsOnLeftBarSide)
    {
        app = application;
        assert(app != nullptr);

        setMinimumSize(style::window::default_body_width, style::window::calendar::item::checkBox::height);
        setMargins(gui::Margins(0,
                                style::window::calendar::item::checkBox::margin_top,
                                0,
                                style::window::calendar::item::checkBox::margin_bottom));
        setMargins(gui::Margins(style::margins::small, style::window::calendar::item::checkBox::margin_top, 0, 0));
        setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);

        hBox = new gui::HBox(this, 0, 0, 0, 0);


@@ 53,15 50,14 @@ namespace gui
                [=]() { app->getCurrentWindow()->bottomBarRestoreFromTemporaryMode(); },
                checkIsOnLeftBarSide);
        }
        checkBox->setMinimumSize(style::window::calendar::item::checkBox::height,
        checkBox->setMinimumSize(style::window::calendar::item::checkBox::input_box_label_w,
                                 style::window::calendar::item::checkBox::height);
        checkBox->activeItem = false;

        descriptionLabel = new gui::Label(hBox, 0, 0, 0, 0);
        descriptionLabel->setMinimumSize(style::window::calendar::item::checkBox::description_label_w,
                                         style::window::calendar::item::checkBox::description_label_h);
        descriptionLabel->setMargins(
            gui::Margins(style::window::calendar::item::checkBox::description_margin, 0, 0, 0));
                                         style::window::calendar::item::checkBox::height);
        descriptionLabel->setMargins(gui::Margins(style::margins::very_big, 0, 0, 0));
        descriptionLabel->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
        descriptionLabel->setFont(style::window::font::medium);


@@ 69,6 65,9 @@ namespace gui
        descriptionLabel->setText(description);

        applyCallbacks();
        if (checkBoxData != nullptr) {
            setCheckBoxes();
        }
    }

    void CheckBoxWithLabelItem::applyCallbacks()


@@ 92,8 91,31 @@ namespace gui
            }
            return false;
        };
    }

        onLoadCallback = [&]() { checkBox->setImageVisible(false); };
    void CheckBoxWithLabelItem::setCheckBoxes()
    {
        if (descriptionLabel->getText() == utils::localize.get(style::strings::common::Monday)) {
            checkBox->setImageVisible(checkBoxData->getData(date::Monday.iso_encoding() - 1));
        }
        else if (descriptionLabel->getText() == utils::localize.get(style::strings::common::Tuesday)) {
            checkBox->setImageVisible(checkBoxData->getData(date::Tuesday.iso_encoding() - 1));
        }
        else if (descriptionLabel->getText() == utils::localize.get(style::strings::common::Wednesday)) {
            checkBox->setImageVisible(checkBoxData->getData(date::Wednesday.iso_encoding() - 1));
        }
        else if (descriptionLabel->getText() == utils::localize.get(style::strings::common::Thursday)) {
            checkBox->setImageVisible(checkBoxData->getData(date::Thursday.iso_encoding() - 1));
        }
        else if (descriptionLabel->getText() == utils::localize.get(style::strings::common::Friday)) {
            checkBox->setImageVisible(checkBoxData->getData(date::Friday.iso_encoding() - 1));
        }
        else if (descriptionLabel->getText() == utils::localize.get(style::strings::common::Saturday)) {
            checkBox->setImageVisible(checkBoxData->getData(date::Saturday.iso_encoding() - 1));
        }
        else if (descriptionLabel->getText() == utils::localize.get(style::strings::common::Sunday)) {
            checkBox->setImageVisible(checkBoxData->getData(date::Sunday.iso_encoding() - 1));
        }
    }

    bool CheckBoxWithLabelItem::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim)

M module-apps/application-calendar/widgets/CheckBoxWithLabelItem.hpp => module-apps/application-calendar/widgets/CheckBoxWithLabelItem.hpp +5 -1
@@ 1,6 1,7 @@
#pragma once
#include "CalendarListItem.hpp"
#include "Application.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include <Label.hpp>
#include <Image.hpp>
#include <BoxLayout.hpp>


@@ 13,14 14,17 @@ namespace gui
    {
        gui::HBox *hBox           = nullptr;
        app::Application *app     = nullptr;
        std::shared_ptr<WeekDaysRepeatData> checkBoxData = nullptr;
        bool checkIsOnLeftBarSide = false;

        virtual void applyCallbacks();
        void setCheckBoxes();

      public:
        CheckBoxWithLabelItem(app::Application *application,
                              const std::string &description,
                              bool checkIsOnLeftBarSide = false);
                              std::shared_ptr<WeekDaysRepeatData> data = nullptr,
                              bool checkIsOnLeftBarSide                = false);
        virtual ~CheckBoxWithLabelItem() override = default;

        gui::Label *descriptionLabel = nullptr;

M module-apps/application-calendar/widgets/DayEventsItem.cpp => module-apps/application-calendar/widgets/DayEventsItem.cpp +14 -13
@@ 1,8 1,9 @@
#include "DayEventsItem.hpp"
#include "CalendarStyle.hpp"
#include "application-calendar/data/TimeDisplayParser.hpp"
#include <ListView.hpp>
#include <gui/widgets/Label.hpp>
#include <Style.hpp>
#include <time/time_conversion.hpp>

namespace gui
{


@@ 10,30 11,30 @@ namespace gui
    DayEventsItem::DayEventsItem()
    {
        setMinimumSize(style::window::default_body_width, style::window::calendar::item::dayEvents::height);
        setMargins(gui::Margins(0, style::margins::small, 0, 0));

        vBox = new gui::VBox(this, 0, 0, 0, 0);
        vBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        hBox = new gui::HBox(vBox, 0, 0, 0, 0);
        hBox->setMinimumSize(style::window::default_body_width, style::window::calendar::item::dayEvents::h_box_h);
        hBox->setMargins(gui::Margins(0, style::window::calendar::item::dayEvents::margins, 0, 0));
        hBox->setMinimumSize(style::window::default_body_width, style::window::calendar::item::dayEvents::box_height);
        hBox->setMargins(gui::Margins(0, style::margins::small + style::margins::big, 0, 0));
        hBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);

        title = new gui::Label(hBox, 0, 0, 0, 0);
        title->setMinimumSize(style::window::calendar::item::dayEvents::title_w,
                              style::window::calendar::item::dayEvents::h_box_h);
        title->setMargins(gui::Margins(0, 0, style::window::calendar::item::dayEvents::margins, 0));
                              style::window::calendar::item::dayEvents::box_height);
        title->setMargins(gui::Margins(style::margins::small, 0, style::margins::small + style::margins::big, 0));
        title->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        title->setFont(style::window::font::bigbold);
        title->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});

        clock = new gui::Image("small_tick");
        clock = new gui::Image(hBox, 0, 0, 0, 0, "small_tick_W_M");
        clock->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});
        hBox->addWidget(clock);

        description = new gui::Label(vBox, 0, 0, 0, 0);
        description->setMinimumSize(style::window::default_body_width,
                                    style::window::calendar::item::dayEvents::description_h);
        description->setMargins(gui::Margins(0, 0, 0, style::window::calendar::item::dayEvents::margins));
                                    style::window::calendar::item::dayEvents::box_height);
        description->setMargins(gui::Margins(style::margins::small, style::margins::big, 0, style::margins::very_big));
        description->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        description->setFont(style::window::font::medium);
        description->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});


@@ 45,10 46,10 @@ namespace gui

        if (rec != nullptr) {
            description->setText(this->record->title.c_str());
            uint32_t start_time = this->record->date_from % 10000;
            uint32_t end_time   = this->record->date_till % 10000;
            std::string text    = std::to_string(start_time) + " - " + std::to_string(end_time);
            title->setText(text);
            title->setText(TimeDisplayParser().getTimeString(record));
            if (record->reminder == static_cast<uint32_t>(Reminder::never)) {
                clock->setVisible(false);
            }
        }
    }


M module-apps/application-calendar/widgets/DayEventsItem.hpp => module-apps/application-calendar/widgets/DayEventsItem.hpp +2 -2
@@ 1,10 1,10 @@
#pragma once

#include "application-calendar/models/DayEventsModel.hpp"
#include <Label.hpp>
#include <ListItem.hpp>
#include <module-db/Interface/EventsRecord.hpp>
#include <BoxLayout.hpp>
#include <module-gui/gui/widgets/Image.hpp>
#include <Image.hpp>

namespace gui


A module-apps/application-calendar/widgets/DayLabel.cpp => module-apps/application-calendar/widgets/DayLabel.cpp +116 -0
@@ 0,0 1,116 @@
#include "DayLabel.hpp"
#include "application-calendar/ApplicationCalendar.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/widgets/MonthBox.hpp"
#include "application-calendar/data/CalendarData.hpp"
#include <time/time_conversion.hpp>

namespace gui
{
    DayLabel::DayLabel(app::Application *app,
                       gui::Item *parent,
                       const uint32_t &cellIndex,
                       const uint32_t &firstWeekOffset,
                       const uint32_t &width,
                       const uint32_t &height,
                       bool isDayEmpty)
        : Rect(parent, 0, 0, width, height)
    {
        this->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);

        this->vBox = new gui::VBox(this, 0, 0, 0, 0);
        this->vBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);

        this->dayNumber = new gui::Label(this->vBox, 0, 0, 0, 0);
        this->dayNumber->setMinimumSize(width, height - 22);
        this->dayNumber->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        this->dayNumber->setAlignment(
            gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        this->dayNumber->setMargins(gui::Margins(0, 11, 0, 0));
        this->dayNumber->activeItem = false;

        this->dotImage = new gui::Image(this, width / 2 - 3, height - 12, 0, 0, "event_dot");
        this->dotImage->setMinimumSize(11, 11);
        this->dotImage->setAlignment(
            gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        this->dotImage->setVisible(false);

        if (cellIndex < style::window::calendar::week_days_number) {
            this->dayNumber->setText(utils::time::Locale::get_short_day(cellIndex));
            this->dayNumber->setFont(style::window::font::verysmall);
            this->activeItem = false;
        }
        else if (cellIndex >= style::window::calendar::week_days_number &&
                 cellIndex < style::window::calendar::week_days_number + firstWeekOffset) {
            this->setPenWidth(style::window::default_border_no_focus_w);
            this->activeItem = false;
        }
        else {
            auto actualMonthBox = dynamic_cast<gui::MonthBox *>(parent);
            assert(actualMonthBox != nullptr);

            uint32_t numb = cellIndex - firstWeekOffset - style::window::calendar::week_days_number + 1;
            date::year_month_day actualDate = TimePointToYearMonthDay(TimePointNow());
            std::string number              = std::to_string(numb);
            if (!isDayEmpty) {
                this->dotImage->setVisible(true);
            }
            this->dayNumber->setText(number);
            this->activeItem = true;
            if (numb == unsigned(actualDate.day()) &&
                (actualMonthBox->monthFilterValue.month() == actualDate.month()) &&
                actualMonthBox->monthFilterValue.year() == actualDate.year()) {
                this->dayNumber->setFont(style::window::font::mediumbold);
            }
            else {
                this->dayNumber->setFont(style::window::font::medium);
            }
            this->activatedCallback = [=](gui::Item &item) {
                auto data       = std::make_unique<DayMonthData>();
                auto month      = actualMonthBox->month;
                auto dateFilter = actualMonthBox->monthFilterValue.year() / actualMonthBox->monthFilterValue.month() /
                                  date::day(numb);
                auto filter = TimePointFromYearMonthDay(dateFilter);
                data->setData(number + " " + month, filter);
                if (isDayEmpty) {
                    auto application = dynamic_cast<app::ApplicationCalendar *>(app);
                    assert(application != nullptr);
                    auto name = data->getDayMonthText();
                    application->switchToNoEventsWindow(name, filter, style::window::calendar::name::day_events_window);
                }
                else {
                    LOG_DEBUG("Switch to DayEventsWindow");
                    app->switchWindow(style::window::calendar::name::day_events_window, std::move(data));
                }
                return true;
            };
            this->setPenWidth(style::window::default_border_no_focus_w);
            this->setPenFocusWidth(style::window::default_border_focus_w);
            this->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_TOP | RectangleEdgeFlags::GUI_RECT_EDGE_BOTTOM);
        }
    }

    uint32_t DayLabel::getDayNumber()
    {
        std::string text = dayNumber->getText();
        try {
            auto result = std::stoi(text.c_str());
            if (result == 0 || result > max_month_day) {
                LOG_ERROR("Wrong day number!");
                return 0;
            }
            return result;
        }
        catch (std::exception &e) {
            LOG_ERROR("DayLabel::getDayNumber: %s", e.what());
            return 0;
        }
    }

    bool DayLabel::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim)
    {
        this->vBox->setPosition(0, 0);
        this->vBox->setSize(newDim.w, newDim.h);
        return true;
    }
} /* namespace gui */

A module-apps/application-calendar/widgets/DayLabel.hpp => module-apps/application-calendar/widgets/DayLabel.hpp +28 -0
@@ 0,0 1,28 @@
#pragma once
#include "Application.hpp"
#include <BoxLayout.hpp>

namespace gui
{

    class DayLabel : public Rect
    {
        gui::VBox *vBox       = nullptr;
        gui::Label *dayNumber = nullptr;
        gui::Image *dotImage  = nullptr;

      public:
        DayLabel(app::Application *app,
                 gui::Item *parent,
                 const uint32_t &cellIndex,
                 const uint32_t &firstWeekOffset,
                 const uint32_t &width,
                 const uint32_t &height,
                 bool isDayEmpty);
        ~DayLabel() override = default;

        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;
        uint32_t getDayNumber();
    };

} /* namespace gui */

M module-apps/application-calendar/widgets/EventDetailDescriptionItem.cpp => module-apps/application-calendar/widgets/EventDetailDescriptionItem.cpp +12 -12
@@ 1,7 1,9 @@
#include "EventDetailDescriptionItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/data/TimeDisplayParser.hpp"
#include <Style.hpp>
#include <Utils.hpp>
#include <time/time_conversion.hpp>
#include <module-utils/date/include/date/date.h>

namespace gui
{


@@ 11,7 13,7 @@ namespace gui
        setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        setMinimumSize(style::window::default_body_width, style::window::calendar::item::eventDetail::height_min);
        setMaximumSize(style::window::default_body_width, style::window::calendar::item::eventDetail::height_max);
        setMargins(gui::Margins(0, style::window::calendar::item::eventDetail::margin_top, 0, 0));
        setMargins(gui::Margins(style::margins::small, style::window::calendar::item::eventDetail::margin_top, 0, 0));

        vBox = new VBox(this, 0, 0, 0, 0);
        vBox->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);


@@ 26,22 28,20 @@ namespace gui

        eventTime = new gui::Label(vBox, 0, 0, 0, 0);
        eventTime->setMinimumSize(style::window::default_body_width,
                                  style::window::calendar::item::eventDetail::event_time_h);
                                  style::window::calendar::item::eventDetail::label_h);
        eventTime->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        eventTime->setMargins(gui::Margins(0,
                                           style::window::calendar::item::eventDetail::margin_top,
                                           0,
                                           style::window::calendar::item::eventDetail::margin_bottom));
        eventTime->setMargins(
            gui::Margins(0, style::window::calendar::item::eventDetail::event_time_margin, 0, style::margins::small));
        eventTime->setFont(style::window::font::bigbold);
        eventTime->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});
        eventTime->activeItem = false;

        description = new gui::Text(vBox, 0, 0, 0, 0);
        description->setMinimumSize(style::window::default_body_width,
                                    style::window::calendar::item::eventDetail::description_h);
                                    style::window::calendar::item::eventDetail::label_h);
        description->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        description->setMaximumSize(style::window::default_body_width,
                                    2 * style::window::calendar::item::eventDetail::description_h);
                                    2 * style::window::calendar::item::eventDetail::label_h);
        description->setFont(style::window::font::big);
        description->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});
        description->setEditMode(EditMode::BROWSE);


@@ 64,9 64,9 @@ namespace gui
    void EventDetailDescriptionItem::descriptionHandler()
    {
        title->setText(utils::localize.get("app_calendar_event_detail"));
        onLoadCallback = [&]() {
            description->setText("Football with folks at School");
            eventTime->setText("12:45 - 1:45 PM");
        onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
            description->setText(event->title);
            eventTime->setText(TimeDisplayParser().getTimeString(event));
        };
    }


M module-apps/application-calendar/widgets/EventTimeItem.cpp => module-apps/application-calendar/widgets/EventTimeItem.cpp +243 -20
@@ 2,7 2,8 @@
#include "application-calendar/widgets/CalendarStyle.hpp"
#include <ListView.hpp>
#include <Style.hpp>
#include <Utils.hpp>
#include <time/time_conversion.hpp>
#include <module-utils/date/include/date/date.h>

namespace gui
{


@@ 17,7 18,7 @@ namespace gui
        setMinimumSize(style::window::default_body_width, style::window::calendar::item::eventTime::height);

        setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        setMargins(gui::Margins(0, style::window::calendar::item::eventTime::margin, 0, 0));
        setMargins(gui::Margins(style::margins::small, style::window::calendar::item::eventTime::margin, 0, 0));

        vBox = new gui::VBox(this, 0, 0, 0, 0);
        vBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);


@@ 25,7 26,7 @@ namespace gui

        descriptionLabel = new gui::Label(vBox, 0, 0, 0, 0);
        descriptionLabel->setMinimumSize(style::window::default_body_width,
                                         style::window::calendar::item::eventTime::description_label_h);
                                         style::window::calendar::item::eventTime::separator);
        descriptionLabel->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
        descriptionLabel->setFont(style::window::font::small);


@@ 34,7 35,7 @@ namespace gui
        hBox = new gui::HBox(vBox, 0, 0, 0, 0);
        hBox->setMinimumSize(style::window::default_body_width,
                             style::window::calendar::item::eventTime::height -
                                 style::window::calendar::item::eventTime::description_label_h);
                                 style::window::calendar::item::eventTime::separator);
        hBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        hBox->activeItem = false;



@@ 48,9 49,9 @@ namespace gui
        hourInput->setEditMode(gui::EditMode::EDIT);

        colonLabel = new gui::Label(hBox, 0, 0, 0, 0);
        colonLabel->setMinimumSize(style::window::calendar::item::eventTime::colon_label_w,
        colonLabel->setMinimumSize(style::window::calendar::item::eventTime::separator,
                                   style::window::calendar::item::eventTime::height -
                                       style::window::calendar::item::eventTime::description_label_h);
                                       style::window::calendar::item::eventTime::separator);
        colonLabel->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        colonLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        colonLabel->setFont(style::window::font::medium);


@@ 70,6 71,9 @@ namespace gui

        focusChangedCallback = [&](Item &item) {
            setFocusItem(focus ? hBox : nullptr);
            if (!item.focus) {
                validateHour();
            }
            return true;
        };



@@ 89,15 93,74 @@ namespace gui
            }

            if (focusedItem->onInput(event)) {
                if (mode24H && atoi(hourInput->getText().c_str()) > timeConstants::max_hour_24H_mode) {
                uint32_t hours;
                uint32_t minutes;
                uint32_t autofill_hour;

                try {
                    hours = std::stoi(hourInput->getText().c_str());
                }
                catch (std::exception &e) {
                    LOG_ERROR("EventTimeItem::applyInputCallbacks hours: %s", e.what());
                    return true;
                }

                try {
                    minutes = std::stoi(minuteInput->getText().c_str());
                }
                catch (std::exception &e) {
                    LOG_ERROR("EventTimeItem::applyInputCallbacks minutes: %s", e.what());
                    return true;
                }

                if (mode24H && hours > style::window::calendar::time::max_hour_24H_mode) {
                    hourInput->setText("00");
                }
                else if (!mode24H && atoi(hourInput->getText().c_str()) > timeConstants::max_hour_12H_mode) {
                else if (!mode24H && hours > style::window::calendar::time::max_hour_12H_mode) {
                    hourInput->setText("12");
                }
                if (atoi(minuteInput->getText().c_str()) > timeConstants::max_minutes) {
                if (minutes > style::window::calendar::time::max_minutes) {
                    minuteInput->setText("00");
                }

                autofill_hour = hours + 1;
                if (this->descriptionLabel->getText() ==
                        utils::localize.get("app_calendar_new_edit_event_start").c_str() &&
                    !mode24H) {
                    if (mode12hInput->getText() == timeConstants::after_noon) {
                        if (autofill_hour == style::window::calendar::time::max_hour_12H_mode) {
                            autofill_hour = style::window::calendar::time::max_hour_12H_mode - 1;
                            secondItem->minuteInput->setText(
                                std::to_string(style::window::calendar::time::max_minutes));
                        }
                        else {
                            secondItem->minuteInput->setText(minuteInput->getText());
                        }
                        secondItem->mode12hInput->setText(mode12hInput->getText());
                    }
                    else {
                        if (autofill_hour == style::window::calendar::time::max_hour_12H_mode) {
                            secondItem->mode12hInput->setText(timeConstants::after_noon);
                        }
                        secondItem->minuteInput->setText(minuteInput->getText());
                    }
                    if (autofill_hour > style::window::calendar::time::max_hour_12H_mode) {
                        autofill_hour = 1;
                        secondItem->mode12hInput->setText(mode12hInput->getText());
                        secondItem->minuteInput->setText(minuteInput->getText());
                    }
                    secondItem->hourInput->setText(std::to_string(autofill_hour));
                }
                else if (this->descriptionLabel->getText() ==
                             utils::localize.get("app_calendar_new_edit_event_start").c_str() &&
                         mode24H) {
                    secondItem->minuteInput->setText(minuteInput->getText());
                    if (autofill_hour > style::window::calendar::time::max_hour_24H_mode) {
                        autofill_hour = style::window::calendar::time::max_hour_24H_mode;
                        secondItem->minuteInput->setText(minuteInput->getText());
                    }
                    secondItem->hourInput->setText(std::to_string(autofill_hour));
                }
                return true;
            }
            else if (hBox->onInput(event)) {


@@ 107,6 170,23 @@ namespace gui
            return false;
        };

        onSaveCallback = [&](std::shared_ptr<EventsRecord> record) {
            validateHour();
            auto hours   = std::chrono::hours(std::stoi(hourInput->getText().c_str()));
            auto minutes = std::chrono::minutes(std::stoi(minuteInput->getText().c_str()));
            if (!mode24H) {
                hours = date::make24(hours, isPm(mode12hInput->getText()));
            }
            if (this->descriptionLabel->getText() == utils::localize.get("app_calendar_new_edit_event_end")) {
                auto time         = TimePointToHourMinSec(record->date_till);
                record->date_till = record->date_till - time.hours() - time.minutes() + hours + minutes;
            }
            else if (this->descriptionLabel->getText() == utils::localize.get("app_calendar_new_edit_event_start")) {
                auto time         = TimePointToHourMinSec(record->date_from);
                record->date_from = record->date_from - time.hours() - time.minutes() + hours + minutes;
            }
        };

        hourInput->inputCallback = [&](Item &item, const InputEvent &event) {
            if (event.state != gui::InputEvent::State::keyReleasedShort) {
                return false;


@@ 170,29 250,62 @@ namespace gui

            mode12hInput->setMinimumSize(style::window::calendar::item::eventTime::time_input_12h_w,
                                         style::window::calendar::item::eventTime::height -
                                             style::window::calendar::item::eventTime::description_label_h);
            mode12hInput->setMargins(
                gui::Margins(style::window::calendar::item::eventTime::mode12h_input_margin, 0, 0, 0));
                                             style::window::calendar::item::eventTime::separator);
            mode12hInput->setMargins(gui::Margins(style::window::calendar::item::eventTime::separator, 0, 0, 0));
            hourInput->setMinimumSize(style::window::calendar::item::eventTime::time_input_12h_w,
                                      style::window::calendar::item::eventTime::height -
                                          style::window::calendar::item::eventTime::description_label_h);
                                          style::window::calendar::item::eventTime::separator);
            minuteInput->setMinimumSize(style::window::calendar::item::eventTime::time_input_12h_w,
                                        style::window::calendar::item::eventTime::height -
                                            style::window::calendar::item::eventTime::description_label_h);
                                            style::window::calendar::item::eventTime::separator);

            onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
                if (this->descriptionLabel->getText() == utils::localize.get("app_calendar_new_edit_event_start")) {
                    auto start_time = TimePointToHourMinSec(event->date_from);

                    hourInput->setText(std::to_string(date::make12(start_time.hours()).count()));
                    minuteInput->setText(std::to_string(start_time.minutes().count()));
                    if (date::is_am(start_time.hours())) {
                        mode12hInput->setText(timeConstants::before_noon);
                    }
                    else {
                        mode12hInput->setText(timeConstants::after_noon);
                    }
                }
                else if (this->descriptionLabel->getText() == utils::localize.get("app_calendar_new_edit_event_end")) {
                    auto end_time = TimePointToHourMinSec(event->date_till);

            onLoadCallback = [&]() {};
            onSaveCallback = [&]() {};
                    hourInput->setText(std::to_string(date::make12(end_time.hours()).count()));
                    minuteInput->setText(std::to_string(end_time.minutes().count()));
                    if (date::is_am(end_time.hours())) {
                        mode12hInput->setText(timeConstants::before_noon);
                    }
                    else {
                        mode12hInput->setText(timeConstants::after_noon);
                    }
                }
            };
        }
        else {
            hourInput->setMinimumSize(style::window::calendar::item::eventTime::time_input_24h_w,
                                      style::window::calendar::item::eventTime::height -
                                          style::window::calendar::item::eventTime::description_label_h);
                                          style::window::calendar::item::eventTime::separator);
            minuteInput->setMinimumSize(style::window::calendar::item::eventTime::time_input_24h_w,
                                        style::window::calendar::item::eventTime::height -
                                            style::window::calendar::item::eventTime::description_label_h);
                                            style::window::calendar::item::eventTime::separator);

            onLoadCallback = [&]() {};
            onSaveCallback = [&]() {};
            onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
                if (this->descriptionLabel->getText() == utils::localize.get("app_calendar_new_edit_event_start")) {
                    auto start_time = TimePointToHourMinSec(event->date_from);
                    hourInput->setText(std::to_string(date::make12(start_time.hours()).count()));
                    minuteInput->setText(std::to_string(start_time.minutes().count()));
                }
                else if (this->descriptionLabel->getText() == utils::localize.get("app_calendar_new_edit_event_end")) {
                    auto end_time = TimePointToHourMinSec(event->date_till);
                    hourInput->setText(std::to_string(date::make12(end_time.hours()).count()));
                    minuteInput->setText(std::to_string(end_time.minutes().count()));
                }
            };
        }
    }



@@ 203,4 316,114 @@ namespace gui
        return true;
    }

    void EventTimeItem::setConnectionToSecondItem(gui::EventTimeItem *item)
    {
        this->secondItem = item;
    }

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

    void EventTimeItem::validateHour()
    {
        if (descriptionLabel->getText() == utils::localize.get("app_calendar_new_edit_event_end")) {
            std::chrono::hours start_hour;
            std::chrono::hours end_hour;
            uint32_t start_minutes;
            uint32_t end_minutes;
            try {
                start_hour = date::make24(std::chrono::hours(std::stoi(secondItem->hourInput->getText().c_str())),
                                          isPm(secondItem->mode12hInput->getText()));
            }
            catch (std::exception &e) {
                LOG_ERROR("EventTimeItem::validateHour start_hour: %s", e.what());
                start_hour = TimePointToHourMinSec(TimePointNow()).hours();
            }

            try {
                end_hour = date::make24(std::chrono::hours(std::stoi(hourInput->getText().c_str())),
                                        isPm(mode12hInput->getText()));
            }
            catch (std::exception &e) {
                LOG_ERROR("EventTimeItem::validateHour end_hour: %s", e.what());
                end_hour = start_hour + std::chrono::hours{1};
            }

            try {
                start_minutes = std::stoi(secondItem->minuteInput->getText().c_str());
            }
            catch (std::exception &e) {
                LOG_ERROR("EventTimeItem::validateHour start_minutes: %s", e.what());
                start_minutes = TimePointToHourMinSec(TimePointNow()).minutes().count();
            }

            try {
                end_minutes = std::stoi(minuteInput->getText().c_str());
            }
            catch (std::exception &e) {
                LOG_ERROR("EventTimeItem::validateHour end_minutes: %s", e.what());
                end_minutes = start_minutes;
            }

            if (!mode24H) {
                validateHourFor12hMode(start_hour, end_hour, start_minutes, end_minutes);
            }
            else {
                validateHourFor24hMode(start_hour, end_hour, start_minutes, end_minutes);
            }
        }
    }

    void EventTimeItem::validateHourFor12hMode(std::chrono::hours start_hour,
                                               std::chrono::minutes end_hour,
                                               uint32_t start_minutes,
                                               uint32_t end_minutes)
    {
        if (start_hour > end_hour || (start_hour == end_hour && start_minutes > end_minutes)) {
            auto hour = start_hour.count() + 1;
            if (secondItem->mode12hInput->getText() == timeConstants::after_noon) {
                if (hour == style::window::calendar::time::max_hour_12H_mode) {
                    hour = style::window::calendar::time::max_hour_12H_mode - 1;
                    minuteInput->setText(std::to_string(style::window::calendar::time::max_minutes));
                }
                else {
                    minuteInput->setText(secondItem->minuteInput->getText());
                }
                mode12hInput->setText(secondItem->mode12hInput->getText());
            }
            else {
                if (hour == style::window::calendar::time::max_hour_12H_mode) {
                    mode12hInput->setText(timeConstants::after_noon);
                }
                minuteInput->setText(minuteInput->getText());
            }
            if (hour > style::window::calendar::time::max_hour_12H_mode) {
                hour = 1;
                mode12hInput->setText(secondItem->mode12hInput->getText());
                minuteInput->setText(secondItem->minuteInput->getText());
            }
            hourInput->setText(std::to_string(hour));
        }
    }

    void EventTimeItem::validateHourFor24hMode(std::chrono::hours start_hour,
                                               std::chrono::minutes end_hour,
                                               uint32_t start_minutes,
                                               uint32_t end_minutes)
    {
        if (start_hour > end_hour || (start_hour == end_hour && start_minutes > end_minutes)) {
            auto hour = start_hour.count() + 1;
            if (hour > style::window::calendar::time::max_hour_24H_mode) {
                hour = style::window::calendar::time::max_hour_24H_mode;
                minuteInput->setText(std::to_string(style::window::calendar::time::max_minutes));
            }
            else {
                minuteInput->setText(secondItem->minuteInput->getText());
            }
            hourInput->setText(std::to_string(hour));
        }
    }

} /* namespace gui */

M module-apps/application-calendar/widgets/EventTimeItem.hpp => module-apps/application-calendar/widgets/EventTimeItem.hpp +12 -3
@@ 8,9 8,6 @@ namespace gui
{
    namespace timeConstants
    {
        const inline int max_hour_24H_mode   = 23;
        const inline int max_hour_12H_mode   = 12;
        const inline int max_minutes         = 59;
        const inline std::string before_noon = "AM";
        const inline std::string after_noon  = "PM";
    } // namespace timeConstants


@@ 24,12 21,23 @@ namespace gui
        gui::Text *minuteInput       = nullptr;
        gui::Label *mode12hInput     = nullptr;
        bool mode24H                 = false;
        gui::EventTimeItem *secondItem = nullptr;

        std::function<void(const UTF8 &text)> bottomBarTemporaryMode = nullptr;
        std::function<void()> bottomBarRestoreFromTemporaryMode      = nullptr;

        void applyInputCallbacks();
        void prepareForTimeMode();
        bool isPm(const std::string &text);
        void validateHour();
        void validateHourFor12hMode(std::chrono::hours start_hour,
                                    std::chrono::minutes end_hour,
                                    uint32_t start_minutes,
                                    uint32_t end_minutes);
        void validateHourFor24hMode(std::chrono::hours start_hour,
                                    std::chrono::minutes end_hour,
                                    uint32_t start_minutes,
                                    uint32_t end_minutes);

      public:
        EventTimeItem(const std::string &description,


@@ 38,6 46,7 @@ namespace gui
                      std::function<void()> bottomBarRestoreFromTemporaryMode      = nullptr);
        virtual ~EventTimeItem() override = default;

        void setConnectionToSecondItem(gui::EventTimeItem *item);
        // virtual methods from Item
        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;
    };

A module-apps/application-calendar/widgets/MonthBox.cpp => module-apps/application-calendar/widgets/MonthBox.cpp +80 -0
@@ 0,0 1,80 @@
#include "MonthBox.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/windows/CalendarMainWindow.hpp"
#include "application-calendar/widgets/DayLabel.hpp"

namespace gui
{
    MonthBox::MonthBox(app::Application *app,
                       gui::Item *parent,
                       const int &offsetTop,
                       const uint32_t &width,
                       const uint32_t &height,
                       const uint32_t &dayWidth,
                       const uint32_t &dayHeight,
                       const std::unique_ptr<MonthModel> &model,
                       bool *isDayEmpty)
        : GridLayout(parent, style::window::default_left_margin, offsetTop, width, height, {dayWidth, dayHeight})
    {
        LOG_DEBUG("Call MonthBox constructor");

        assert(parent);
        parent->addWidget(this);
        month            = model->getMonthText();
        monthFilterValue = model->getYear() / model->getMonth();
        grid.x           = dayWidth;
        grid.y           = dayHeight;

        uint32_t firstDayOffset = model->getFirstWeekOffset();
        uint32_t lastDay        = model->getLastDay();
        uint32_t iterations     = style::window::calendar::week_days_number + firstDayOffset + lastDay;

        uint32_t i;
        for (i = 0; i < iterations; ++i) {
            if (i < style::window::calendar::week_days_number + firstDayOffset) {
                auto day = new DayLabel(app,
                                        this,
                                        i,
                                        firstDayOffset,
                                        style::window::calendar::day_cell_width,
                                        style::window::calendar::day_cell_height,
                                        true);
                addWidget(day);
            }
            else {
                auto day = new DayLabel(app,
                                        this,
                                        i,
                                        firstDayOffset,
                                        style::window::calendar::day_cell_width,
                                        style::window::calendar::day_cell_height,
                                        isDayEmpty[i - (style::window::calendar::week_days_number + firstDayOffset)]);
                addWidget(day);
            }
        }
        auto mainWindow = dynamic_cast<CalendarMainWindow *>(parent);
        if (mainWindow->returnedFromWindow) {
            focusChangedCallback = [=](Item &item) {
                YearMonthDay date = monthFilterValue.year() / monthFilterValue.month() / date::last;
                if (unsigned(date.day()) < mainWindow->dayFocusedBefore) {
                    setFocusOnElement(unsigned(date.day()) - 1);
                }
                else {
                    setFocusOnElement(mainWindow->dayFocusedBefore - 1);
                }
                return true;
            };
        }
        else {
            date::year_month_day actualDate = TimePointToYearMonthDay(TimePointNow());
            if (model->getYear() == actualDate.year() && model->getMonth() == actualDate.month()) {
                focusChangedCallback = [=](Item &item) {
                    setFocusOnElement(unsigned(actualDate.day()) - 1);
                    return true;
                };
            }
        }

        LOG_DEBUG("MonthBox constructor Completed Successfully!");
    }
} /* namespace gui */

A module-apps/application-calendar/widgets/MonthBox.hpp => module-apps/application-calendar/widgets/MonthBox.hpp +26 -0
@@ 0,0 1,26 @@
#pragma once
#include "Application.hpp"
#include <gui/widgets/GridLayout.hpp>
#include "application-calendar/models/MonthModel.hpp"

namespace gui
{
    class MonthBox : public GridLayout
    {
      public:
        MonthBox(app::Application *app,
                 gui::Item *parent,
                 const int &offsetTop,
                 const uint32_t &width,
                 const uint32_t &height,
                 const uint32_t &dayWidth,
                 const uint32_t &dayHeight,
                 const std::unique_ptr<MonthModel> &model,
                 bool *isDayEmpty);

        ~MonthBox() override = default;
        std::string month;
        date::year_month monthFilterValue;
    };

} /* namespace gui */

R module-apps/application-calendar/widgets/CheckBoxWithLabelAndModel.cpp => module-apps/application-calendar/widgets/NewEventCheckBoxWithLabel.cpp +26 -5
@@ 1,20 1,23 @@
#include "CheckBoxWithLabelAndModel.hpp"
#include "NewEventCheckBoxWithLabel.hpp"

namespace gui
{

    CheckBoxWithLabelAndModel::CheckBoxWithLabelAndModel(app::Application *application,
    NewEventCheckBoxWithLabel::NewEventCheckBoxWithLabel(app::Application *application,
                                                         const std::string &description,
                                                         bool checkIsOnLeftBarSide,
                                                         NewEditEventModel *model)
        : CheckBoxWithLabelItem(application, description, checkIsOnLeftBarSide), model(model)
        : CheckBoxWithLabelItem(application, description, nullptr, checkIsOnLeftBarSide), model(model)
    {
        app = application;
        assert(app != nullptr);

        setMargins(gui::Margins(
            style::margins::small, style::window::calendar::item::checkBox::margin_top, 0, style::margins::small));
        applyCallbacks();
    }

    void CheckBoxWithLabelAndModel::applyCallbacks()
    void NewEventCheckBoxWithLabel::applyCallbacks()
    {
        focusChangedCallback = [&](Item &item) {
            if (focus) {


@@ 48,7 51,25 @@ namespace gui
            return false;
        };

        onLoadCallback = [&]() { checkBox->setImageVisible(false); };
        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() == style::window::calendar::time::max_hour_24H_mode &&
                end_time.minutes().count() == style::window::calendar::time::max_minutes) {
                checkBox->setImageVisible(true);
            }
        };
        onSaveCallback = [&](std::shared_ptr<EventsRecord> event) {
            if (checkBox->isChecked()) {
                auto event_start = TimePointToHourMinSec(event->date_from);
                event->date_from =
                    event->date_from - event_start.hours() - event_start.minutes() - event_start.seconds();
                event->date_till = event->date_from +
                                   std::chrono::hours(style::window::calendar::time::max_hour_24H_mode) +
                                   std::chrono::minutes(style::window::calendar::time::max_minutes);
            }
        };
    }

} /* namespace gui */

R module-apps/application-calendar/widgets/CheckBoxWithLabelAndModel.hpp => module-apps/application-calendar/widgets/NewEventCheckBoxWithLabel.hpp +3 -3
@@ 4,18 4,18 @@

namespace gui
{
    class CheckBoxWithLabelAndModel : public CheckBoxWithLabelItem
    class NewEventCheckBoxWithLabel : public CheckBoxWithLabelItem
    {
        NewEditEventModel *model = nullptr;
        app::Application *app    = nullptr;
        void applyCallbacks() override;

      public:
        CheckBoxWithLabelAndModel(app::Application *application,
        NewEventCheckBoxWithLabel(app::Application *application,
                                  const std::string &description,
                                  bool checkIsOnLeftBarSide = false,
                                  NewEditEventModel *model  = nullptr);
        virtual ~CheckBoxWithLabelAndModel() override = default;
        virtual ~NewEventCheckBoxWithLabel() override = default;
    };

} /* namespace gui */

M module-apps/application-calendar/widgets/RepeatAndReminderItem.cpp => module-apps/application-calendar/widgets/RepeatAndReminderItem.cpp +14 -6
@@ 2,11 2,12 @@
#include "application-calendar/widgets/CalendarStyle.hpp"
#include <Style.hpp>
#include <Utils.hpp>
#include <module-apps/application-calendar/ApplicationCalendar.hpp>

namespace gui
{

    RepeatAndReminderItem::RepeatAndReminderItem()
    RepeatAndReminderItem::RepeatAndReminderItem(app::ApplicationCalendar *application) : app(application)
    {
        activeItem = false;
        setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);


@@ 40,7 41,7 @@ namespace gui
        repeat->setMinimumSize(style::window::calendar::item::repeatAndReminder::description_w,
                               style::window::calendar::item::repeatAndReminder::description_h);
        repeat->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        repeat->setFont(style::window::font::small);
        repeat->setFont(style::window::font::medium);
        repeat->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});
        repeat->activeItem = false;



@@ 59,7 60,7 @@ namespace gui
        reminder->setMinimumSize(style::window::default_body_width / 2,
                                 style::window::calendar::item::repeatAndReminder::description_h);
        reminder->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        reminder->setFont(style::window::font::small);
        reminder->setFont(style::window::font::medium);
        reminder->setAlignment(gui::Alignment{gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center});
        reminder->activeItem = false;



@@ 77,9 78,16 @@ namespace gui
    {
        repeatTitle->setText(utils::localize.get("app_calendar_event_detail_repeat"));
        reminderTitle->setText(utils::localize.get("app_calendar_event_detail_reminder"));
        onLoadCallback = [&]() {
            repeat->setText(utils::localize.get("app_calendar_repeat_daily"));
            reminder->setText(utils::localize.get("app_calendar_reminder_1_week_before"));
        onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
            if (event->repeat >= app::ApplicationCalendar::repeatOptions.size()) {
                repeat->setText("app_calendar_custom_repeat_title");
            }
            else {
                repeat->setText(utils::localize.get(
                    app::ApplicationCalendar::repeatOptions.at(static_cast<Repeat>(event->repeat))));
            }
            reminder->setText(utils::localize.get(
                app::ApplicationCalendar::reminderOptions.at(static_cast<Reminder>(event->reminder))));
        };
    }


M module-apps/application-calendar/widgets/RepeatAndReminderItem.hpp => module-apps/application-calendar/widgets/RepeatAndReminderItem.hpp +4 -1
@@ 3,6 3,8 @@
#include <Label.hpp>
#include <Text.hpp>
#include <BoxLayout.hpp>
#include <module-apps/Application.hpp>
#include <module-apps/application-calendar/ApplicationCalendar.hpp>

namespace gui



@@ 16,9 18,10 @@ namespace gui
        gui::Label *repeat        = nullptr;
        gui::Label *reminderTitle = nullptr;
        gui::Label *reminder      = nullptr;
        app::ApplicationCalendar *app = nullptr;

      public:
        RepeatAndReminderItem();
        RepeatAndReminderItem(app::ApplicationCalendar *application);
        virtual ~RepeatAndReminderItem() = default;

        void descriptionHandler();

M module-apps/application-calendar/widgets/SeveralOptionsItem.cpp => module-apps/application-calendar/widgets/SeveralOptionsItem.cpp +54 -14
@@ 1,7 1,11 @@
#include "SeveralOptionsItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "module-apps/application-calendar/ApplicationCalendar.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include "module-apps/application-calendar/data/OptionParser.hpp"
#include <Style.hpp>
#include <Utils.hpp>
#include <module-db/Interface/EventsRecord.hpp>

namespace gui
{


@@ 20,15 24,15 @@ namespace gui

        setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_BOTTOM);
        setPenWidth(style::window::default_border_rect_no_focus);
        setMargins(gui::Margins(0, style::window::calendar::item::severalOptions::margin, 0, 0));
        setMargins(gui::Margins(style::margins::small, style::margins::huge / 2, 0, style::margins::huge / 2));

        vBox = new gui::VBox(this, 0, 0, 0, 0);
        vBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        vBox->activeItem = false;

        descriptionLabel = new gui::Label(vBox, 0, 0, 0, 0);
        descriptionLabel->setMinimumSize(style::window::calendar::item::severalOptions::description_label_w,
                                         style::window::calendar::item::severalOptions::description_label_h);
        descriptionLabel->setMinimumSize(style::window::default_body_width,
                                         style::window::calendar::item::severalOptions::label_h);
        descriptionLabel->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
        descriptionLabel->setFont(style::window::font::small);


@@ 38,30 42,30 @@ namespace gui
        hBox = new gui::HBox(vBox, 0, 0, 0, 0);
        hBox->setMinimumSize(style::window::default_body_width,
                             style::window::calendar::item::severalOptions::height -
                                 style::window::calendar::item::severalOptions::description_label_h);
                                 style::window::calendar::item::severalOptions::label_h);
        hBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        hBox->activeItem = false;

        leftArrow = new gui::Image(hBox, 0, 0, 0, 0);
        leftArrow->setMinimumSize(style::window::calendar::item::severalOptions::arrow_w,
                                  style::window::calendar::item::severalOptions::arrow_h);
        leftArrow->setMinimumSize(style::window::calendar::item::severalOptions::arrow_w_h,
                                  style::window::calendar::item::severalOptions::arrow_w_h);
        leftArrow->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
        leftArrow->activeItem = false;
        leftArrow->set("arrow_left");

        optionLabel = new gui::Label(hBox, 0, 0, 0, 0);
        optionLabel->setMinimumSize(style::window::default_body_width -
                                        2 * style::window::calendar::item::severalOptions::arrow_w,
                                        2 * style::window::calendar::item::severalOptions::arrow_w_h,
                                    style::window::calendar::item::severalOptions::height -
                                        style::window::calendar::item::severalOptions::description_label_h);
                                        style::window::calendar::item::severalOptions::label_h);
        optionLabel->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        optionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
        optionLabel->setFont(style::window::font::small);
        optionLabel->setFont(style::window::font::medium);
        optionLabel->activeItem = false;

        rightArrow = new gui::Image(hBox, 0, 0, 0, 0);
        rightArrow->setMinimumSize(style::window::calendar::item::severalOptions::arrow_w,
                                   style::window::calendar::item::severalOptions::arrow_h);
        rightArrow->setMinimumSize(style::window::calendar::item::severalOptions::arrow_w_h,
                                   style::window::calendar::item::severalOptions::arrow_w_h);
        rightArrow->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
        rightArrow->activeItem = false;
        rightArrow->set("arrow_right");


@@ 94,13 98,12 @@ namespace gui
            optionsNames.push_back(utils::localize.get("app_calendar_repeat_year"));
            optionsNames.push_back(utils::localize.get("app_calendar_repeat_custom"));
        }
        optionLabel->setText(optionsNames[0]);
    }

    void SeveralOptionsItem::applyCallbacks()
    {
        focusChangedCallback = [&](Item &item) {
            if (focus) {
            if (item.focus) {
                if (actualVectorIndex == optionsNames.size() - 1 &&
                    descriptionLabel->getText() == utils::localize.get("app_calendar_event_detail_repeat")) {
                    bottomBarTemporaryMode(utils::localize.get("app_calendar_edit"));


@@ 147,11 150,48 @@ namespace gui
            }
            if (event.keyCode == gui::KeyCode::KEY_LF && actualVectorIndex == optionsNames.size() - 1 &&
                descriptionLabel->getText() == utils::localize.get("app_calendar_event_detail_repeat")) {
                application->switchWindow(style::window::calendar::name::custom_repeat_window);
                OptionParser parser;
                auto weekDayRepeatData = std::make_unique<WeekDaysRepeatData>();
                assert(weekDayRepeatData != nullptr);
                auto weekDayData = parser.setWeekDayOptions(repeatOptionValue, std::move(weekDayRepeatData));
                application->switchWindow(style::window::calendar::name::custom_repeat_window, std::move(weekDayData));
                return true;
            }
            return false;
        };

        onSaveCallback = [&](std::shared_ptr<EventsRecord> record) {
            if (descriptionLabel->getText() == utils::localize.get("app_calendar_event_detail_repeat")) {
                if (record->repeat < optionsNames.size() - 1 || actualVectorIndex < optionsNames.size() - 1) {
                    record->repeat = actualVectorIndex;
                }
            }
            else if (descriptionLabel->getText() == utils::localize.get("app_calendar_event_detail_reminder")) {
                record->reminder = static_cast<uint32_t>(reminderTimeOptions[actualVectorIndex]);
            }
        };

        onLoadCallback = [&](std::shared_ptr<EventsRecord> event) {
            auto calendarApp = dynamic_cast<app::ApplicationCalendar *>(application);
            assert(calendarApp != nullptr);
            if (descriptionLabel->getText() == utils::localize.get("app_calendar_event_detail_repeat")) {
                if (event->repeat < optionsNames.size() - 1) {
                    actualVectorIndex = event->repeat;
                }
                else {
                    actualVectorIndex = optionsNames.size() - 1;
                }
                repeatOptionValue = event->repeat;
                optionLabel->setText(optionsNames[actualVectorIndex]);
            }
            else if (descriptionLabel->getText() == utils::localize.get("app_calendar_event_detail_reminder")) {
                actualVectorIndex = std::find(reminderTimeOptions.begin(),
                                              reminderTimeOptions.end(),
                                              static_cast<Reminder>(event->reminder)) -
                                    reminderTimeOptions.begin();
                optionLabel->setText(optionsNames[actualVectorIndex]);
            }
        };
    }

    bool SeveralOptionsItem::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim)

M module-apps/application-calendar/widgets/SeveralOptionsItem.hpp => module-apps/application-calendar/widgets/SeveralOptionsItem.hpp +16 -0
@@ 1,12 1,25 @@
#pragma once
#include "Application.hpp"
#include "CalendarListItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include <module-apps/application-calendar/data/CalendarData.hpp>
#include <Label.hpp>
#include <Image.hpp>
#include <BoxLayout.hpp>

namespace gui
{
    const std::array<Reminder, 10> reminderTimeOptions = {Reminder::never,
                                                          Reminder::event_time,
                                                          Reminder::five_min_before,
                                                          Reminder::fifteen_min_before,
                                                          Reminder::thirty_min_before,
                                                          Reminder::one_hour_before,
                                                          Reminder::two_hour_before,
                                                          Reminder::one_day_before,
                                                          Reminder::two_days_before,
                                                          Reminder::one_week_before};

    class SeveralOptionsItem : public CalendarListItem
    {
        app::Application *application = nullptr;


@@ 17,6 30,7 @@ namespace gui
        gui::Image *leftArrow         = nullptr;
        gui::Image *rightArrow        = nullptr;
        std::vector<std::string> optionsNames;

        unsigned int actualVectorIndex = 0;

        std::function<void(const UTF8 &text)> bottomBarTemporaryMode = nullptr;


@@ 31,6 45,8 @@ namespace gui

        void prepareOptionsNames();
        void applyCallbacks();
        uint32_t repeatOptionValue = 0;

        // virtual methods from Item
        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;
    };

M module-apps/application-calendar/widgets/TextWithLabelItem.cpp => module-apps/application-calendar/widgets/TextWithLabelItem.cpp +10 -4
@@ 1,6 1,5 @@
#include "TextWithLabelItem.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "windows/AppWindow.hpp"
#include <Style.hpp>

namespace gui


@@ 12,8 11,9 @@ namespace gui
                                         std::function<void()> selectSpecialCharacter)
    {
        setMinimumSize(style::window::default_body_width, style::window::calendar::item::textWithLabel::height);

        setMargins(gui::Margins(style::margins::small, 0, 0, 0));
        setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        bottomBarRestoreFromTemporaryMode();

        vBox = new gui::VBox(this, 0, 0, 0, 0);
        vBox->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);


@@ 23,7 23,7 @@ namespace gui
        descriptionLabel = new gui::Label(vBox, 0, 0, 0, 0);
        descriptionLabel->setMinimumSize(style::window::default_body_width,
                                         style::window::calendar::item::textWithLabel::description_h);
        descriptionLabel->setMargins(gui::Margins(0, style::window::calendar::item::textWithLabel::margin, 0, 0));
        descriptionLabel->setMargins(gui::Margins(0, style::margins::small, 0, 0));
        descriptionLabel->setEdges(gui::RectangleEdgeFlags::GUI_RECT_EDGE_NO_EDGES);
        descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Top));
        descriptionLabel->setFont(style::window::font::small);


@@ 50,7 50,13 @@ namespace gui
            return true;
        };

        inputCallback = [&](Item &item, const InputEvent &event) { return textInput->onInput(event); };
        inputCallback = [&](Item &item, const InputEvent &event) {
            auto ret       = textInput->onInput(event);
            onSaveCallback = [&](std::shared_ptr<EventsRecord> record) { record->title = textInput->getText(); };
            return ret;
        };

        onLoadCallback = [&](std::shared_ptr<EventsRecord> event) { textInput->setText(event->title); };
    }

    bool TextWithLabelItem::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim)

M module-apps/application-calendar/windows/AllEventsWindow.cpp => module-apps/application-calendar/windows/AllEventsWindow.cpp +48 -5
@@ 1,9 1,16 @@
#include "AllEventsWindow.hpp"
#include "module-apps/application-calendar/ApplicationCalendar.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include <gui/widgets/Window.hpp>
#include <gui/widgets/BottomBar.hpp>
#include <gui/widgets/TopBar.hpp>
#include <service-appmgr/ApplicationManager.hpp>

#include <module-services/service-db/messages/QueryMessage.hpp>
#include <module-db/queries/calendar/QueryEventsGetAllLimited.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <time/time_conversion.hpp>

namespace gui
{



@@ 41,16 48,18 @@ namespace gui
                                                  style::window::calendar::listView_w,
                                                  style::window::calendar::listView_h,
                                                  allEventsModel);

        allEventsList->setPenFocusWidth(style::window::default_border_no_focus_w);
        allEventsList->setPenWidth(style::window::default_border_no_focus_w);

        setFocusItem(allEventsList);
    }

    void AllEventsWindow::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
    {
        allEventsList->rebuildList();
        auto dataReceived = dynamic_cast<PrevWindowData *>(data);
        if (dataReceived != nullptr) {
            if (dataReceived->getData() == PrevWindowData::PrevWindow::Delete) {
                checkEmpty = true;
            }
        }
    }

    bool AllEventsWindow::onInput(const gui::InputEvent &inputEvent)


@@ 71,8 80,13 @@ namespace gui

        if (inputEvent.keyCode == gui::KeyCode::KEY_LEFT) {
            LOG_DEBUG("Switch to new event window");
            std::unique_ptr<gui::SwitchData> data = std::make_unique<SwitchData>();
            std::unique_ptr<EventRecordData> data = std::make_unique<EventRecordData>();
            data->setDescription("New");
            auto event       = std::make_shared<EventsRecord>();
            event->date_from = TimePointNow();
            event->date_till = TimePointNow();
            data->setData(event);
            data->setWindowName(style::window::calendar::name::all_events_window);
            application->switchWindow(
                style::window::calendar::name::new_edit_event, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;


@@ 86,4 100,33 @@ namespace gui

        return false;
    }

    bool AllEventsWindow::onDatabaseMessage(sys::Message *msgl)
    {
        auto msg = dynamic_cast<db::QueryResponse *>(msgl);
        if (msg != nullptr) {
            auto temp = msg->getResult();
            if (auto response = dynamic_cast<db::query::events::GetAllLimitedResult *>(temp.get())) {
                auto records_data = response->getResult();
                allEventsModel->setRecordsCount(*response->getCountResult());
                auto records = std::make_unique<std::vector<EventsRecord>>(records_data->begin(), records_data->end());
                if (checkEmpty) {
                    if (records->size() == 0) {
                        auto app = dynamic_cast<app::ApplicationCalendar *>(application);
                        assert(application != nullptr);
                        auto filter = std::chrono::system_clock::now();
                        app->switchToNoEventsWindow(utils::localize.get("app_calendar_title_main"),
                                                    filter,
                                                    style::window::calendar::name::all_events_window);
                    }
                }
                application->refreshWindow(RefreshModes::GUI_REFRESH_FAST);
                return allEventsModel->updateRecords(std::move(records));
            }
            LOG_DEBUG("Response False");
            return false;
        }
        LOG_DEBUG("AllEventsWindow DB Message != QueryResponse");
        return false;
    }
} /* namespace gui */

M module-apps/application-calendar/windows/AllEventsWindow.hpp => module-apps/application-calendar/windows/AllEventsWindow.hpp +3 -0
@@ 19,10 19,13 @@ namespace gui
      public:
        AllEventsWindow(app::Application *app, std::string name);
        void onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) override;
        bool onDatabaseMessage(sys::Message *msgl) override;

        bool onInput(const gui::InputEvent &inputEvent) override;
        void rebuild() override;
        void buildInterface() override;

        bool checkEmpty = false;
    };

} // namespace gui

M module-apps/application-calendar/windows/CalendarEventsOptionsWindow.cpp => module-apps/application-calendar/windows/CalendarEventsOptionsWindow.cpp +28 -7
@@ 4,6 4,7 @@
#include <Utils.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <module-db/queries/calendar/QueryEventsRemove.hpp>
#include <module-apps/application-calendar/data/CalendarData.hpp>

namespace gui
{


@@ 12,7 13,6 @@ namespace gui
        : OptionWindow(app, style::window::calendar::name::events_options)
    {
        buildInterface();
        this->addOptions(eventsOptionsList());
    }

    auto CalendarEventsOptions::eventsOptionsList() -> std::list<gui::Option>


@@ 20,10 20,11 @@ namespace gui
        std::list<gui::Option> options;
        options.emplace_back(gui::Option{utils::localize.get("app_calendar_options_edit"), [=](gui::Item &item) {
                                             LOG_INFO("Switch to edit window");
                                             std::unique_ptr<gui::SwitchData> data = std::make_unique<SwitchData>();
                                             auto rec  = std::make_unique<EventsRecord>(*eventRecord);
                                             auto data = std::make_unique<EventRecordData>(std::move(rec));
                                             data->setDescription("Edit");
                                             data->setWindowName(goBackWindowName);
                                             application->switchWindow(style::window::calendar::name::new_edit_event,
                                                                       gui::ShowMode::GUI_SHOW_INIT,
                                                                       std::move(data));
                                             return true;
                                         }});


@@ 32,6 33,24 @@ namespace gui
        return options;
    }

    auto CalendarEventsOptions::handleSwitchData(SwitchData *data) -> bool
    {
        if (data == nullptr) {
            return false;
        }

        auto *item = dynamic_cast<EventRecordData *>(data);
        if (item == nullptr) {
            return false;
        }

        eventRecord      = item->getData();
        goBackWindowName = item->getWindowName();
        clearOptions();
        addOptions(eventsOptionsList());
        return true;
    }

    auto CalendarEventsOptions::eventDelete() -> bool
    {
        LOG_DEBUG("Switch to delete event window");


@@ 40,14 59,16 @@ namespace gui
        assert(dialog != nullptr);
        auto meta   = dialog->meta;
        meta.action = [=]() -> bool {
            LOG_INFO("Detele calendar event");
            uint32_t mockID = 2;
            LOG_INFO("Delete calendar event %d", static_cast<int>(eventRecord->ID));
            DBServiceAPI::GetQuery(
                application, db::Interface::Name::Events, std::make_unique<db::query::events::Remove>(mockID));
                application, db::Interface::Name::Events, std::make_unique<db::query::events::Remove>(eventRecord->ID));
            auto data = make_unique<PrevWindowData>();
            data->setData(PrevWindowData::PrevWindow::Delete);
            application->switchWindow(goBackWindowName, std::move(data));
            return true;
        };
        meta.text  = utils::localize.get("app_calendar_event_delete_confirmation");
        meta.title = "Football with folks";
        meta.title = eventRecord->title;
        meta.icon  = "phonebook_contact_delete_trashcan";
        dialog->update(meta);
        this->application->switchWindow(dialog->getName());

M module-apps/application-calendar/windows/CalendarEventsOptionsWindow.hpp => module-apps/application-calendar/windows/CalendarEventsOptionsWindow.hpp +6 -0
@@ 1,13 1,19 @@
#pragma once

#include <module-db/Interface/EventsRecord.hpp>
#include "OptionWindow.hpp"

namespace gui
{
    class CalendarEventsOptions : public OptionWindow
    {
        std::shared_ptr<EventsRecord> eventRecord;
        std::string goBackWindowName;

      public:
        CalendarEventsOptions(app::Application *app);
        ~CalendarEventsOptions() override = default;
        auto handleSwitchData(SwitchData *data) -> bool override;

      private:
        auto eventsOptionsList() -> std::list<gui::Option>;

M module-apps/application-calendar/windows/CalendarMainWindow.cpp => module-apps/application-calendar/windows/CalendarMainWindow.cpp +78 -127
@@ 2,8 2,7 @@
#include "application-calendar/ApplicationCalendar.hpp"
#include "application-calendar/models/MonthModel.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/models/DayEventsModel.hpp"
#include "application-calendar/models/AllEventsModel.hpp"
#include "application-calendar/data/CalendarData.hpp"
#include "NoEvents.hpp"
#include <module-services/service-db/messages/QueryMessage.hpp>
#include <module-db/queries/calendar/QueryEventsGetAll.hpp>


@@ 13,81 12,6 @@

namespace gui
{
    DayLabel::DayLabel(app::Application *app,
                       gui::Item *parent,
                       const uint32_t &cellIndex,
                       const uint32_t &firstWeekOffset,
                       const uint32_t &width,
                       const uint32_t &height)
        : Label(parent, 0, 0, 0, 0, "")
    {
        parent->addWidget(this);
        this->setSize(width, height);

        if (cellIndex < style::window::calendar::week_days_number) {
            this->setText(utils::time::Locale::get_short_day(cellIndex));
            this->setFont(style::window::font::verysmall);
            this->setPenWidth(style::window::default_border_no_focus_w);
            this->activeItem = false;
        }
        else if (cellIndex >= style::window::calendar::week_days_number &&
                 cellIndex < style::window::calendar::week_days_number + firstWeekOffset) {
            this->setPenWidth(style::window::default_border_no_focus_w);
            this->activeItem = false;
        }
        else {
            std::string number =
                std::to_string(cellIndex - firstWeekOffset - style::window::calendar::week_days_number + 1);
            this->setText(number);
            this->activeItem = true;
            this->setFont(style::window::font::medium);
            this->activatedCallback = [=](gui::Item &item) {
                LOG_DEBUG("Switch to DayEventsWindow");
                app->switchWindow("DayEventsWindow", nullptr);
                return true;
            };
            this->setPenWidth(style::window::default_border_no_focus_w);
            this->setPenFocusWidth(style::window::default_border_focus_w);
            this->setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_TOP | RectangleEdgeFlags::GUI_RECT_EDGE_BOTTOM);
            this->setFont(style::window::font::medium);
        }
        this->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));
    }

    MonthBox::MonthBox(app::Application *app,
                       gui::Item *parent,
                       const int &offsetTop,
                       const uint32_t &width,
                       const uint32_t &height,
                       const uint32_t &dayWidth,
                       const uint32_t &dayHeight,
                       const std::unique_ptr<MonthModel> &model)
        : GridLayout(parent, style::window::default_left_margin, offsetTop, width, height, {dayWidth, dayHeight})
    {
        LOG_DEBUG("Call MonthBox constructor");

        assert(parent);
        parent->addWidget(this);
        grid.x = dayWidth;
        grid.y = dayHeight;

        uint32_t firstDayOffset = model->getFirstWeekOffset();
        uint32_t lastDay        = model->getLastDay();
        uint32_t iterations     = style::window::calendar::week_days_number + firstDayOffset + lastDay;

        uint32_t i;
        for (i = 0; i < iterations; ++i) {
            auto day = new DayLabel(app,
                                    this,
                                    i,
                                    firstDayOffset,
                                    style::window::calendar::day_cell_width,
                                    style::window::calendar::day_cell_height);
            addWidget(day);
        }

        LOG_DEBUG("MonthBox constructor Completed Successfully!");
    }

    CalendarMainWindow::CalendarMainWindow(app::Application *app, std::string name) : AppWindow(app, name)
    {


@@ 96,13 20,14 @@ namespace gui
        std::chrono::system_clock::time_point tp =
            std::chrono::system_clock::from_time_t(appCalendar->getCurrentTimeStamp());
        this->actualDate = date::year_month_day{date::floor<date::days>(tp)};
        std::fill(begin(isDayEmpty), end(isDayEmpty), true);
        buildInterface();
    }

    void CalendarMainWindow::refresh()
    {
        erase(dateLabel);
        month->erase();
        monthBox->erase();

        monthModel           = std::make_unique<MonthModel>(actualDate);
        std::string dateText = monthModel->getMonthYearText();


@@ 128,11 53,12 @@ namespace gui
        dayHeight     = style::window::calendar::day_cell_height;

        // create empty month box
        month = new MonthBox(app, this, offsetFromTop, monthWidth, monthHeight, dayWidth, dayHeight, monthModel);
        monthBox = new MonthBox(
            app, this, offsetFromTop, monthWidth, monthHeight, dayWidth, dayHeight, monthModel, isDayEmpty);
        // setup month box
        addWidget(month);
        addWidget(monthBox);

        month->borderCallback = [this](const InputEvent &inputEvent) -> bool {
        monthBox->borderCallback = [this](const InputEvent &inputEvent) -> bool {
            if (inputEvent.state != InputEvent::State::keyReleasedShort) {
                return false;
            }


@@ 148,7 74,8 @@ namespace gui
                    date::year prevYear   = --actualDate.year();
                    actualDate            = prevYear / prevMonth / date::last;
                }
                this->refresh();

                filterRequest();
                return true;
            }
            case KeyCode::KEY_DOWN: {


@@ 162,28 89,29 @@ namespace gui
                    date::year nextYear   = ++actualDate.year();
                    actualDate            = nextYear / nextMonth / 1;
                }
                this->refresh();

                filterRequest();
                return true;
            }
            case KeyCode::KEY_LEFT: {
                LOG_DEBUG("Call borderCallback -> go to the previous element");
                auto it = month->getNavigationFocusedItem();
                if (month->nextNavigationItem(std::prev(it)) != nullptr) {
                    month->setFocusItem(month->nextNavigationItem(std::prev(it)));
                auto it = monthBox->getNavigationFocusedItem();
                if (monthBox->nextNavigationItem(std::prev(it)) != nullptr) {
                    monthBox->setFocusItem(monthBox->nextNavigationItem(std::prev(it)));
                }
                else {
                    month->setFocusOnLastElement();
                    monthBox->setFocusOnLastElement();
                }
                return true;
            }
            case KeyCode::KEY_RIGHT: {
                LOG_DEBUG("Call borderCallback -> go to the next element");
                auto it = month->getNavigationFocusedItem();
                if (month->nextNavigationItem(std::next(it)) != nullptr) {
                    month->setFocusItem(month->nextNavigationItem(std::next(it)));
                auto it = monthBox->getNavigationFocusedItem();
                if (monthBox->nextNavigationItem(std::next(it)) != nullptr) {
                    monthBox->setFocusItem(monthBox->nextNavigationItem(std::next(it)));
                }
                else {
                    month->setFocusOnElement(0);
                    monthBox->setFocusOnElement(0);
                }
                return true;
            }


@@ 193,7 121,7 @@ namespace gui
            }
        };

        setFocusItem(month);
        setFocusItem(monthBox);
    }

    void CalendarMainWindow::buildDateLabel(std::string actualDateTime)


@@ 217,12 145,11 @@ namespace gui
        AppWindow::buildInterface();

        LOG_DEBUG("Start build interface for calendar main window");
        [[maybe_unused]] auto app = dynamic_cast<app::ApplicationCalendar *>(application);
        assert(app != nullptr);

        setTitle(utils::localize.get("app_calendar_title_main"));

        monthModel = std::make_unique<MonthModel>(actualDate);
        filterRequest();
        this->buildMonth(monthModel);
        this->buildDateLabel(monthModel->getMonthYearText());



@@ 249,49 176,73 @@ namespace gui
            return false;
        }

        if (inputEvent.keyCode == gui::KeyCode::KEY_ENTER) {
            std::shared_ptr<DayEventsModel> dayEventsModel = std::make_shared<DayEventsModel>(this->application);
            if (dayEventsModel->requestRecordsCount() == 0) {
                switchToNoEventsWindow();
            }
            else {
                LOG_DEBUG("Switch to Day Window");
                application->switchWindow(style::window::calendar::name::day_events_window);
            }
        if (inputEvent.keyCode == gui::KeyCode::KEY_LF) {
            DBServiceAPI::GetQuery(
                application, db::Interface::Name::Events, std::make_unique<db::query::events::GetAll>());
            return true;
        }

        if (inputEvent.keyCode == gui::KeyCode::KEY_LF) {
            std::shared_ptr<AllEventsModel> allEventsModel = std::make_shared<AllEventsModel>(this->application);
            if (allEventsModel->requestRecordsCount() == 0) {
                switchToNoEventsWindow();
        return false;
    }

    void CalendarMainWindow::filterRequest()
    {
        YearMonthDay date_from = actualDate.year() / actualDate.month() / 1;
        YearMonthDay date_till = date_from + date::months{1};
        auto filter_from       = TimePointFromYearMonthDay(date_from);
        auto filter_till       = TimePointFromYearMonthDay(date_till);
        LOG_DEBUG("filter:  %s", TimePointToString(filter_till).c_str());
        DBServiceAPI::GetQuery(application,
                               db::Interface::Name::Events,
                               std::make_unique<db::query::events::GetFiltered>(filter_from, filter_till));
    }

    bool CalendarMainWindow::onDatabaseMessage(sys::Message *msgl)
    {
        std::fill(begin(isDayEmpty), end(isDayEmpty), true);
        auto msg = dynamic_cast<db::QueryResponse *>(msgl);
        if (msg != nullptr) {
            auto temp = msg->getResult();
            if (auto response = dynamic_cast<db::query::events::GetFilteredResult *>(temp.get())) {
                unique_ptr<vector<EventsRecord>> records = response->getResult();
                for (auto &rec : *records) {
                    date::year_month_day recordDate = TimePointToYearMonthDay(rec.date_from);
                    uint32_t dayNumb                = static_cast<unsigned>(recordDate.day());
                    isDayEmpty[dayNumb - 1]         = false;
                }
                refresh();
                return true;
            }
            else {
                LOG_DEBUG("Switch to List Window");
                application->switchWindow(style::window::calendar::name::all_events_window);
            if (auto response = dynamic_cast<db::query::events::GetAllResult *>(temp.get())) {
                unique_ptr<vector<EventsRecord>> records = response->getResult();
                if (records->size() != 0) {
                    application->switchWindow(style::window::calendar::name::all_events_window);
                }
                else {
                    auto appCalendar = dynamic_cast<app::ApplicationCalendar *>(application);
                    assert(appCalendar != nullptr);
                    auto filter = TimePointFromYearMonthDay(actualDate);
                    appCalendar->switchToNoEventsWindow(utils::localize.get("app_calendar_title_main"),
                                                        filter,
                                                        style::window::calendar::name::all_events_window);
                }
                return true;
            }
            return true;
            LOG_DEBUG("Response False");
            return false;
        }

        LOG_DEBUG("Calendar MainWindow DB Message != QueryResponse");
        return false;
    }

    void CalendarMainWindow::switchToNoEventsWindow()
    void CalendarMainWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        auto dialog = dynamic_cast<gui::NoEvents *>(
            this->application->getWindow(style::window::calendar::name::no_events_window));
        assert(dialog != nullptr);
        auto meta   = dialog->meta;
        meta.text   = "app_calendar_no_events_information";
        meta.title  = utils::time::Time().str("%d %B");
        meta.icon   = "phonebook_empty_grey_circle_W_G";
        meta.action = [=]() -> bool {
            LOG_DEBUG("Switch to edit window");
            return true;
        };
        dialog->update(meta);
        this->application->switchWindow(dialog->getName());
        LOG_DEBUG("Switch to no events window");
        if (mode == ShowMode::GUI_SHOW_RETURN) {
            returnedFromWindow = true;
            auto day           = dynamic_cast<DayLabel *>(monthBox->getFocusItem());
            dayFocusedBefore   = day->getDayNumber();
        }
        filterRequest();
    }

} // namespace gui

M module-apps/application-calendar/windows/CalendarMainWindow.hpp => module-apps/application-calendar/windows/CalendarMainWindow.hpp +13 -30
@@ 4,6 4,8 @@
#include "Application.hpp"
#include "application-calendar/ApplicationCalendar.hpp"
#include "application-calendar/models/MonthModel.hpp"
#include "application-calendar/widgets/DayLabel.hpp"
#include "application-calendar/widgets/MonthBox.hpp"
#include <gui/widgets/GridLayout.hpp>
#include <map>
#include <vector>


@@ 11,37 13,10 @@

namespace gui
{
    class CalendarMainWindow;

    class DayLabel : public Label
    {
      public:
        DayLabel(app::Application *app,
                 gui::Item *parent,
                 const uint32_t &cellIndex,
                 const uint32_t &firstWeekOffset,
                 const uint32_t &width,
                 const uint32_t &height);
        ~DayLabel() override = default;
    };

    class MonthBox : public GridLayout
    {
      public:
        MonthBox(app::Application *app,
                 gui::Item *parent,
                 const int &offsetTop,
                 const uint32_t &width,
                 const uint32_t &height,
                 const uint32_t &dayWidth,
                 const uint32_t &dayHeight,
                 const std::unique_ptr<MonthModel> &model);

        ~MonthBox() override = default;
    };

    class CalendarMainWindow : public gui::AppWindow
    {
        bool isDayEmpty[31];
        uint32_t offsetFromTop = 0;
        uint32_t monthWidth    = 0;
        uint32_t monthHeight   = 0;


@@ 50,7 25,7 @@ namespace gui

      protected:
        date::year_month_day actualDate;
        MonthBox *month = nullptr;
        MonthBox *monthBox = nullptr;
        Label *dateLabel = nullptr;
        std::unique_ptr<MonthModel> monthModel;



@@ 58,14 33,22 @@ namespace gui
        CalendarMainWindow(app::Application *app, std::string name);

        ~CalendarMainWindow() override = default;
        void switchToNoEventsWindow();
        void rebuild() override;
        void refresh();
        void filterRequest();
        void buildMonth(std::unique_ptr<MonthModel> &model);
        void buildDateLabel(std::string actualDateTime);
        void buildInterface() override;
        void destroyInterface() override;
        bool onInput(const gui::InputEvent &inputEvent) override;
        bool onDatabaseMessage(sys::Message *msgl) override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        std::unique_ptr<MonthModel> getMonthModel()
        {
            return std::move(monthModel);
        }
        bool returnedFromWindow   = false;
        uint32_t dayFocusedBefore = 0;
    };

} // namespace gui

M module-apps/application-calendar/windows/CustomRepeatWindow.cpp => module-apps/application-calendar/windows/CustomRepeatWindow.cpp +50 -2
@@ 1,4 1,6 @@
#include "CustomRepeatWindow.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include "application-calendar/widgets/CheckBoxWithLabelItem.hpp"
#include <gui/widgets/Window.hpp>
#include <Utils.hpp>



@@ 29,7 31,7 @@ namespace gui
        setTitle(utils::localize.get("app_calendar_custom_repeat_title"));
        list = new gui::ListView(this,
                                 style::window::calendar::listView_x,
                                 style::window::calendar::listView_y - 8,
                                 style::window::calendar::listView_y,
                                 style::window::calendar::listView_w,
                                 style::window::calendar::listView_h,
                                 customRepeatModel);


@@ 42,7 44,53 @@ namespace gui
            list->rebuildList();
        }

        customRepeatModel->loadData();
        auto recievedData = dynamic_cast<WeekDaysRepeatData *>(data);
        if (recievedData != nullptr) {
            weekDaysOptData = std::make_shared<WeekDaysRepeatData>(*recievedData);
        }
        else {
            weekDaysOptData = std::make_shared<WeekDaysRepeatData>();
        }
        customRepeatModel->loadData(weekDaysOptData);
    }

    bool CustomRepeatWindow::onInput(const InputEvent &inputEvent)
    {
        // check if any of the lower inheritance onInput methods catch the event
        if (Window::onInput(inputEvent)) {
            return true;
        }
        // process only if key is released
        if (!inputEvent.isShortPress())
            return false;

        switch (inputEvent.keyCode) {
        case KeyCode::KEY_RF: {
            if (weekDaysOptData != nullptr) {
                auto items = customRepeatModel->getInternalData();
                uint32_t i = 0;
                for (auto it : items) {
                    auto item = dynamic_cast<CheckBoxWithLabelItem *>(it);
                    if (item && item->checkBox->isChecked()) {
                        weekDaysOptData->setData(i);
                    }
                    ++i;
                }
                auto data = weekDaysOptData.get();
                application->switchWindow(style::window::calendar::name::new_edit_event,
                                          gui::ShowMode::GUI_SHOW_RETURN,
                                          std::make_unique<WeekDaysRepeatData>(*data));
                return true;
            }
            else {
                application->returnToPreviousWindow();
            }
        }
        default:
            break;
        }

        return false;
    }

} /* namespace gui */

M module-apps/application-calendar/windows/CustomRepeatWindow.hpp => module-apps/application-calendar/windows/CustomRepeatWindow.hpp +6 -0
@@ 11,6 11,7 @@ namespace gui
    {
        gui::ListView *list                                  = nullptr;
        std::shared_ptr<CustomRepeatModel> customRepeatModel = nullptr;
        std::shared_ptr<WeekDaysRepeatData> weekDaysOptData  = nullptr;

      public:
        CustomRepeatWindow(app::Application *app, std::string name);


@@ 18,6 19,11 @@ namespace gui
        void rebuild() override;
        void buildInterface() override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        bool onInput(const InputEvent &inputEvent) override;
        void setWeekDaysOptionData(std::unique_ptr<WeekDaysRepeatData> data)
        {
            weekDaysOptData = std::move(data);
        }
    };

} /* namespace gui */

M module-apps/application-calendar/windows/DayEventsWindow.cpp => module-apps/application-calendar/windows/DayEventsWindow.cpp +58 -24
@@ 1,25 1,23 @@
#include "DayEventsWindow.hpp"

#include "application-calendar/data/CalendarData.hpp"
#include "module-apps/application-calendar/ApplicationCalendar.hpp"
#include <gui/widgets/Window.hpp>
#include <gui/widgets/Label.hpp>
#include <gui/widgets/Item.hpp>
#include <gui/widgets/BoxLayout.hpp>
#include <gui/widgets/BottomBar.hpp>
#include <gui/widgets/TopBar.hpp>

#include <time/time_conversion.hpp>
#include <module-services/service-db/messages/QueryMessage.hpp>
#include <module-db/queries/calendar/QueryEventsGetFiltered.hpp>
#include <module-db/queries/calendar/QueryEventsGetAll.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>
#include <module-apps/application-calendar/ApplicationCalendar.hpp>

namespace gui
{

    DayEventsWindow::DayEventsWindow(app::Application *app, std::string name)
        : AppWindow(app, style::window::calendar::name::day_events_window),
          dayEventsModel{std::make_shared<DayEventsModel>(this->application)}
          dayEventsModel{std::make_shared<DayEventsInternalModel>(this->application)}
    {
        buildInterface();
    }


@@ 28,18 26,53 @@ namespace gui
    {
        buildInterface();
    }
    void DayEventsWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        auto filterTill = filterFrom + std::chrono::hours(style::window::calendar::time::max_hour_24H_mode + 1);
        DBServiceAPI::GetQuery(application,
                               db::Interface::Name::Events,
                               std::make_unique<db::query::events::GetFiltered>(filterFrom, filterTill));
        setTitle(dayMonthTitle);
        auto dataReceived = dynamic_cast<PrevWindowData *>(data);
        if (dataReceived != nullptr) {
            if (dataReceived->getData() == PrevWindowData::PrevWindow::Delete) {
                checkEmpty = true;
            }
        }
    }

    auto DayEventsWindow::handleSwitchData(SwitchData *data) -> bool
    {
        if (data == nullptr) {
            return false;
        }

        auto *item = dynamic_cast<DayMonthData *>(data);
        if (item == nullptr) {
            return false;
        }

        dayMonthTitle = item->getDayMonthText();
        filterFrom    = item->getDateFilter();
        LOG_DEBUG("FILTER 1: %s", TimePointToString(filterFrom).c_str());
        setTitle(dayMonthTitle);
        if (dayMonthTitle == "") {
            return false;
        }

        return true;
    }

    void DayEventsWindow::buildInterface()
    {
        AppWindow::buildInterface();

        auto ttime = utils::time::Time();
        topBar->setActive(gui::TopBar::Elements::TIME, true);
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::open));

        setTitle(ttime.str("%d %B"));
        setTitle(dayMonthTitle);
        leftArrowImage = new gui::Image(
            this, style::window::calendar::arrow_x, style::window::calendar::arrow_y, 0, 0, "arrow_left");
        newDayEventImage =


@@ 51,10 84,6 @@ namespace gui
                                          style::window::calendar::listView_w,
                                          style::window::calendar::listView_h,
                                          dayEventsModel);

        dayEventsList->setPenFocusWidth(style::window::default_border_no_focus_w);
        dayEventsList->setPenWidth(style::window::default_border_no_focus_w);

        setFocusItem(dayEventsList);
    }



@@ 70,16 99,14 @@ namespace gui

        if (inputEvent.keyCode == gui::KeyCode::KEY_LEFT) {
            LOG_DEBUG("Switch to new window - edit window");
            auto msg = DBServiceAPI::GetQueryWithReply(
                application, db::Interface::Name::Events, std::make_unique<db::query::events::GetAll>(), 1000);

            LOG_DEBUG("Type id %s", typeid(*msg.second).name());
            auto msgl = msg.second.get();
            assert(msgl != nullptr);
            onDatabaseMessage(msgl);

            std::unique_ptr<gui::SwitchData> data = std::make_unique<SwitchData>();
            std::unique_ptr<EventRecordData> data = std::make_unique<EventRecordData>();
            data->setDescription("New");
            auto rec       = new EventsRecord();
            rec->date_from = filterFrom;
            rec->date_till = filterFrom;
            auto event     = std::make_shared<EventsRecord>(*rec);
            data->setData(event);
            data->setWindowName(style::window::calendar::name::day_events_window);
            application->switchWindow(
                style::window::calendar::name::new_edit_event, gui::ShowMode::GUI_SHOW_INIT, std::move(data));
            return true;


@@ 92,14 119,21 @@ namespace gui
        auto msg = dynamic_cast<db::QueryResponse *>(msgl);
        if (msg != nullptr) {
            auto temp = msg->getResult();
            if (auto response = dynamic_cast<db::query::events::GetAllResult *>(temp.get())) {
            if (auto response = dynamic_cast<db::query::events::GetFilteredResult *>(temp.get())) {
                unique_ptr<vector<EventsRecord>> records = response->getResult();
                for (auto &rec : *records) {
                    LOG_DEBUG("record: %s", rec.title.c_str());
                }
                uint32_t numberOfItems = records->size();
                dayEventsModel->setRecordsCount(numberOfItems);
                return dayEventsModel->updateRecords(std::move(records));
                if (checkEmpty) {
                    if (records->size() == 0) {
                        auto app = dynamic_cast<app::ApplicationCalendar *>(application);
                        assert(application != nullptr);
                        auto name = dayMonthTitle;
                        app->switchToNoEventsWindow(name, filterFrom, style::window::calendar::name::day_events_window);
                    }
                }
                dayEventsModel->loadData(std::move(records));
                application->refreshWindow(RefreshModes::GUI_REFRESH_FAST);
            }
            LOG_DEBUG("Response False");
            return false;

M module-apps/application-calendar/windows/DayEventsWindow.hpp => module-apps/application-calendar/windows/DayEventsWindow.hpp +9 -3
@@ 1,6 1,6 @@
#pragma once

#include "application-calendar/models/DayEventsModel.hpp"
#include "application-calendar/models/DayEventsInternalModel.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "windows/AppWindow.hpp"
#include "Application.hpp"


@@ 9,23 9,29 @@
#include <ListView.hpp>
#include <gui/widgets/Item.hpp>
#include <gui/widgets/Label.hpp>
#include <module-apps/application-calendar/data/dateCommon.hpp>

namespace gui
{
    class DayEventsWindow : public gui::AppWindow
    {
        std::string dayMonthTitle;
        TimePoint filterFrom;
        gui::Image *leftArrowImage                               = nullptr;
        gui::Image *newDayEventImage                             = nullptr;
        gui::ListView *dayEventsList                             = nullptr;
        std::shared_ptr<DayEventsModel> dayEventsModel           = nullptr;
        std::shared_ptr<DayEventsInternalModel> dayEventsModel   = nullptr;

      public:
        DayEventsWindow(app::Application *app, std::string name);

        bool handleSwitchData(SwitchData *data) override;
        bool onInput(const gui::InputEvent &inputEvent) override;
        bool onDatabaseMessage(sys::Message *msgl) override;
        void rebuild() override;
        void buildInterface() override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;

        bool checkEmpty = false;
    };

} /* namespace app */

M module-apps/application-calendar/windows/EventDetailWindow.cpp => module-apps/application-calendar/windows/EventDetailWindow.cpp +27 -4
@@ 1,5 1,6 @@
#include "EventDetailWindow.hpp"
#include "application-calendar/widgets/CalendarStyle.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include <gui/widgets/Window.hpp>
#include <time/time_conversion.hpp>



@@ 29,8 30,6 @@ namespace gui
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::LEFT, utils::localize.get(style::strings::common::options));

        setTitle(utils::time::Time().str("%d %B"));

        bodyList = new gui::ListView(this,
                                     style::window::calendar::listView_x,
                                     style::window::calendar::listView_y,


@@ 47,7 46,28 @@ namespace gui
            bodyList->rebuildList();
        }

        eventDetailModel->loadData();
        eventDetailModel->loadData(eventRecord);
    }

    auto EventDetailWindow::handleSwitchData(SwitchData *data) -> bool
    {
        if (data == nullptr) {
            return false;
        }

        auto *item = dynamic_cast<EventRecordData *>(data);
        if (item == nullptr) {
            return false;
        }

        eventRecord    = item->getData();
        prevWindowName = item->getWindowName();
        auto startDate = TimePointToYearMonthDay(eventRecord->date_from);
        std::string monthStr =
            utils::time::Locale::get_month(utils::time::Locale::Month(unsigned(startDate.month()) - 1));
        setTitle(std::to_string(unsigned(startDate.day())) + " " + monthStr);

        return true;
    }

    bool EventDetailWindow::onInput(const gui::InputEvent &inputEvent)


@@ 62,7 82,10 @@ namespace gui

        if (inputEvent.keyCode == gui::KeyCode::KEY_LF) {
            LOG_DEBUG("Switch to option window");
            application->switchWindow(style::window::calendar::name::events_options);
            auto rec  = std::make_unique<EventsRecord>(*eventRecord);
            auto data = std::make_unique<EventRecordData>(std::move(rec));
            data->setWindowName(prevWindowName);
            application->switchWindow(style::window::calendar::name::events_options, std::move(data));
            return true;
        }


M module-apps/application-calendar/windows/EventDetailWindow.hpp => module-apps/application-calendar/windows/EventDetailWindow.hpp +4 -0
@@ 4,11 4,14 @@
#include "Application.hpp"
#include <Style.hpp>
#include <ListView.hpp>
#include <module-db/Interface/EventsRecord.hpp>

namespace gui
{
    class EventDetailWindow : public gui::AppWindow
    {
        std::string prevWindowName                         = "";
        std::shared_ptr<EventsRecord> eventRecord          = nullptr;
        std::shared_ptr<EventDetailModel> eventDetailModel = nullptr;
        gui::ListView *bodyList                            = nullptr;



@@ 20,6 23,7 @@ namespace gui
        void onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) override;
        void rebuild() override;
        void buildInterface() override;
        auto handleSwitchData(SwitchData *data) -> bool override;
    };

} /* namespace gui */

M module-apps/application-calendar/windows/NewEditEventWindow.cpp => module-apps/application-calendar/windows/NewEditEventWindow.cpp +32 -6
@@ 1,4 1,6 @@
#include "NewEditEventWindow.hpp"
#include <module-db/Interface/EventsRecord.hpp>
#include <module-services/service-db/api/DBServiceAPI.hpp>

namespace gui
{


@@ 40,17 42,31 @@ namespace gui
        switch (eventAction) {
        case EventAction::None:
            break;
        case EventAction::Add:
        case EventAction::Add: {
            setTitle(utils::localize.get("app_calendar_new_event_title"));
            break;
        }
        case EventAction::Edit:
            setTitle(utils::localize.get("app_calendar_edit_event_title"));
            break;
        }

        if (mode == ShowMode::GUI_SHOW_INIT) {
            newEditEventModel->loadData(false);
            list->rebuildList();
            auto rec = dynamic_cast<EventRecordData *>(data);
            if (rec != nullptr) {
                eventRecord    = rec->getData();
                prevWindowName = rec->getWindowName();
            }
            newEditEventModel->loadData(eventRecord);
        }
        if (mode == ShowMode::GUI_SHOW_RETURN) {
            auto receivedData = dynamic_cast<WeekDaysRepeatData *>(data);
            if (receivedData != nullptr) {
                auto parser         = new OptionParser();
                auto uniqueData     = std::make_unique<WeekDaysRepeatData>(*receivedData);
                eventRecord->repeat = eventRecord->repeat + parser->getDatabaseFieldValue(std::move(uniqueData));
                newEditEventModel->loadRepeat(eventRecord);
            }
        }
    }



@@ 65,6 81,16 @@ namespace gui
        }

        if (inputEvent.keyCode == gui::KeyCode::KEY_ENTER) {
            LOG_DEBUG("Save Event");
            bool edit = true;
            if (eventAction == EventAction::Edit) {
                edit = true;
            }
            else if (eventAction == EventAction::Add) {
                edit = false;
            }

            newEditEventModel->saveData(eventRecord, edit, prevWindowName);
            return true;
        }



@@ 77,12 103,12 @@ namespace gui
            return false;
        }

        if (data->getDescription() == "Edit") {
        if (data->getDescription() == style::window::calendar::edit_event) {
            eventAction = EventAction::Edit;
        }
        else if (data->getDescription() == "New") {
        else if (data->getDescription() == style::window::calendar::new_event) {
            eventAction = EventAction::Add;
        }
        return false;
        return true;
    }
} /* namespace gui */

M module-apps/application-calendar/windows/NewEditEventWindow.hpp => module-apps/application-calendar/windows/NewEditEventWindow.hpp +4 -1
@@ 2,6 2,8 @@

#include "application-calendar/widgets/CalendarStyle.hpp"
#include "application-calendar/models/NewEditEventModel.hpp"
#include "module-apps/application-calendar/data/CalendarData.hpp"
#include "module-apps/application-calendar/data/OptionParser.hpp"
#include "windows/AppWindow.hpp"
#include "Application.hpp"
#include <gui/widgets/Item.hpp>


@@ 22,7 24,8 @@ namespace gui
            Add,
            Edit
        };

        std::string prevWindowName                           = "";
        std::shared_ptr<EventsRecord> eventRecord            = nullptr;
        gui::ListView *list                                  = nullptr;
        std::shared_ptr<NewEditEventModel> newEditEventModel = nullptr;
        EventAction eventAction                              = EventAction::None;

M module-apps/application-desktop/windows/DesktopMainWindow.cpp => module-apps/application-desktop/windows/DesktopMainWindow.cpp +0 -1
@@ 116,7 116,6 @@ namespace gui

    void DesktopMainWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {

        // update time
        time->setText(topBar->getTimeString());


M module-db/CMakeLists.txt => module-db/CMakeLists.txt +1 -1
@@ 97,8 97,8 @@ set(SOURCES
        queries/calendar/QueryEventsGetAll.cpp
        queries/calendar/QueryEventsAdd.cpp
        queries/calendar/QueryEventsEdit.cpp
        queries/calendar/QueryEventsGetFiltered.hpp
        queries/calendar/QueryEventsGetFiltered.cpp
        queries/calendar/QueryEventsGetAllLimited.cpp
        queries/settings/QuerySettingsGet_v2.cpp
        queries/settings/QuerySettingsUpdate_v2.cpp
        queries/settings/QuerySettingsAddOrIgnore_v2.cpp

M module-db/Interface/EventsRecord.cpp => module-db/Interface/EventsRecord.cpp +105 -25
@@ 6,14 6,15 @@
#include "module-db/queries/calendar/QueryEventsEdit.hpp"
#include <module-db/queries/calendar/QueryEventsEdit.hpp>
#include <module-db/queries/calendar/QueryEventsGetFiltered.hpp>
#include <module-db/queries/calendar/QueryEventsGetAllLimited.hpp>
#include <log/log.hpp>
#include <Utils.hpp>
#include <cassert>
#include <vector>

EventsRecord::EventsRecord(const EventsTableRow &tableRow)
    : Record{tableRow.ID}, title{tableRow.title}, description{tableRow.description}, date_from{tableRow.date_from},
      date_till{tableRow.date_till}, reminder{tableRow.reminder}, repeat{tableRow.repeat}, time_zone{tableRow.time_zone}
    : Record{tableRow.ID}, title{tableRow.title}, date_from{tableRow.date_from}, date_till{tableRow.date_till},
      reminder{tableRow.reminder}, repeat{tableRow.repeat}
{}

EventsRecordInterface::EventsRecordInterface(EventsDB *eventsDb) : eventsDb(eventsDb)


@@ 21,21 22,44 @@ EventsRecordInterface::EventsRecordInterface(EventsDB *eventsDb) : eventsDb(even

bool EventsRecordInterface::Add(const EventsRecord &rec)
{
    eventsDb->events.add(EventsTableRow{{.ID = rec.ID},
                                        .title       = rec.title,
                                        .description = rec.description,
                                        .date_from   = rec.date_from,
                                        .date_till   = rec.date_till,
                                        .reminder    = rec.reminder,
                                        .repeat      = rec.repeat,
                                        .time_zone   = rec.time_zone});
    auto entry = EventsTableRow{{.ID = rec.ID},
                                .title     = rec.title,
                                .date_from = rec.date_from,
                                .date_till = rec.date_till,
                                .reminder  = rec.reminder,
                                .repeat    = rec.repeat};

    switch (RepeatOption(rec.repeat)) {
    case RepeatOption::Never: {
        return eventsDb->events.add(entry);
    }
    case RepeatOption::Daily: {
        return eventsDb->events.addDaily(entry);
    }
    case RepeatOption::Weekly: {
        return eventsDb->events.addWeekly(entry);
    }
    case RepeatOption::TwoWeeks: {
        return eventsDb->events.addTwoWeeks(entry);
    }
    case RepeatOption::Month: {
        return eventsDb->events.addMonth(entry);
    }
    case RepeatOption::Year: {
        return eventsDb->events.addYear(entry);
    }
    default: {
        break;
        eventsDb->events.addCustom(entry);
    }
    }

    return true;
}

std::unique_ptr<std::vector<EventsRecord>> EventsRecordInterface::Select(uint32_t from, uint32_t till)
std::unique_ptr<std::vector<EventsRecord>> EventsRecordInterface::Select(TimePoint filter_from, TimePoint filter_till)
{
    auto rows = eventsDb->events.selectByDatePeriod(from, till);
    auto rows = eventsDb->events.selectByDatePeriod(filter_from, filter_till);

    auto records = std::make_unique<std::vector<EventsRecord>>();



@@ 73,22 97,65 @@ std::unique_ptr<std::vector<EventsRecord>> EventsRecordInterface::GetLimitOffset
    return records;
}

bool EventsRecordInterface::Update(const EventsRecord &rec, const uint32_t &checkValue)
std::unique_ptr<std::vector<EventsRecord>> EventsRecordInterface::GetLimitOffsetByDate(uint32_t offset, uint32_t limit)
{
    if (limit == 0) {
        limit = GetCount();
    }

    auto rows = eventsDb->events.getLimitOffsetByDate(offset, limit);

    auto records = std::make_unique<std::vector<EventsRecord>>();

    for (auto &r : rows) {
        records->push_back(r);
    }

    return records;
}

bool EventsRecordInterface::Update(const EventsRecord &rec)
{
    auto entry = eventsDb->events.getById(rec.ID);
    if (!entry.isValid() || entry.date_from != checkValue) {
    auto record = eventsDb->events.getById(rec.ID);
    if (!record.isValid()) {
        LOG_DEBUG("IS NOT VALID");
        return false;
    }

    return eventsDb->events.update(EventsTableRow{{.ID = rec.ID},
                                                  .title       = rec.title,
                                                  .description = rec.description,
                                                  .date_from   = rec.date_from,
                                                  .date_till   = rec.date_till,
                                                  .reminder    = rec.reminder,
                                                  .repeat      = rec.repeat,
                                                  .time_zone   = rec.time_zone});
    auto entry = EventsTableRow{{.ID = rec.ID},
                                .title     = rec.title,
                                .date_from = rec.date_from,
                                .date_till = rec.date_till,
                                .reminder  = rec.reminder,
                                .repeat    = rec.repeat};

    bool result = eventsDb->events.update(entry);

    switch (RepeatOption(rec.repeat)) {
    case RepeatOption::Never: {
        return (eventsDb->events.add(entry) && result);
    }
    case RepeatOption::Daily: {
        return (eventsDb->events.addDaily(entry) && result);
    }
    case RepeatOption::Weekly: {
        return (eventsDb->events.addWeekly(entry) && result);
    }
    case RepeatOption::TwoWeeks: {
        return (eventsDb->events.addTwoWeeks(entry) && result);
    }
    case RepeatOption::Month: {
        return (eventsDb->events.addMonth(entry) && result);
    }
    case RepeatOption::Year: {
        return (eventsDb->events.addYear(entry) && result);
    }
    default: {
        break;
        eventsDb->events.addCustom(entry);
    }
    }
    return false;
}

bool EventsRecordInterface::RemoveByID(uint32_t id)


@@ 124,6 191,10 @@ std::unique_ptr<db::QueryResult> EventsRecordInterface::runQuery(std::shared_ptr
        const auto local_query = dynamic_cast<const db::query::events::GetAll *>(query.get());
        return runQueryImpl(local_query);
    }
    if (typeid(*query) == typeid(db::query::events::GetAllLimited)) {
        const auto local_query = dynamic_cast<const db::query::events::GetAllLimited *>(query.get());
        return runQueryImpl(local_query);
    }
    if (typeid(*query) == typeid(db::query::events::GetFiltered)) {
        const auto local_query = dynamic_cast<const db::query::events::GetFiltered *>(query.get());
        return runQueryImpl(local_query);


@@ 157,10 228,19 @@ std::unique_ptr<db::query::events::GetAllResult> EventsRecordInterface::runQuery
    return std::make_unique<db::query::events::GetAllResult>(std::move(records));
}

std::unique_ptr<db::query::events::GetAllLimitedResult> EventsRecordInterface::runQueryImpl(
    const db::query::events::GetAllLimited *query)
{
    auto count   = GetCount();
    auto records = GetLimitOffsetByDate(query->offset, query->limit);
    return std::make_unique<db::query::events::GetAllLimitedResult>(std::move(records),
                                                                    std::make_unique<uint32_t>(count));
}

std::unique_ptr<db::query::events::GetFilteredResult> EventsRecordInterface::runQueryImpl(
    const db::query::events::GetFiltered *query)
{
    auto records = Select(query->date_from, query->date_till);
    auto records = Select(query->filter_from, query->filter_till);
    return std::make_unique<db::query::events::GetFilteredResult>(std::move(records));
}



@@ 179,6 259,6 @@ std::unique_ptr<db::query::events::RemoveResult> EventsRecordInterface::runQuery

std::unique_ptr<db::query::events::EditResult> EventsRecordInterface::runQueryImpl(const db::query::events::Edit *query)
{
    bool ret = Update(query->getRecord(), query->getDateFrom());
    bool ret = Update(query->getRecord());
    return std::make_unique<db::query::events::EditResult>(ret);
}

M module-db/Interface/EventsRecord.hpp => module-db/Interface/EventsRecord.hpp +19 -10
@@ 6,6 6,7 @@
#include <utf8/UTF8.hpp>
#include <cstdint>
#include <vector>
#include <module-apps/application-calendar/data/dateCommon.hpp>

// fw declarations
namespace db::query::events


@@ 14,6 15,8 @@ namespace db::query::events
    class GetResult;
    class GetAll;
    class GetAllResult;
    class GetAllLimited;
    class GetAllLimitedResult;
    class GetFiltered;
    class GetFilteredResult;
    class Add;


@@ 25,19 28,23 @@ namespace db::query::events

} // namespace db::query::events

enum class RepeatOption
{
    Never    = 0,
    Daily    = 1,
    Weekly   = 2,
    TwoWeeks = 3,
    Month    = 4,
    Year     = 5
};

struct EventsRecord : public Record
{
    std::string title;
    std::string description;
    // date and time when event will begin
    uint32_t date_from = 0;
    // date and time when event will end
    uint32_t date_till = 0;
    // date and time of the event reminder
    TimePoint date_from;
    TimePoint date_till;
    uint32_t reminder = 0;
    // repeat the event daily
    uint32_t repeat    = 0;
    uint32_t time_zone = 0;

    EventsRecord()  = default;
    ~EventsRecord() = default;


@@ 60,15 67,16 @@ class EventsRecordInterface : public RecordInterface<EventsRecord, EventsRecordF
    bool Add(const EventsRecord &rec) override final;
    bool RemoveByID(uint32_t id) override final;
    bool RemoveByField(EventsRecordField field, const char *str) override final;
    bool Update(const EventsRecord &rec, const uint32_t &dateFromCheckVal);
    bool Update(const EventsRecord &rec);
    EventsRecord GetByID(uint32_t id) override final;
    uint32_t GetCount() override final;
    std::unique_ptr<std::vector<EventsRecord>> Select(uint32_t from, uint32_t till);
    std::unique_ptr<std::vector<EventsRecord>> Select(TimePoint filter_from, TimePoint filter_till);
    std::unique_ptr<std::vector<EventsRecord>> GetLimitOffset(uint32_t offset, uint32_t limit) override final;
    std::unique_ptr<std::vector<EventsRecord>> GetLimitOffsetByField(uint32_t offset,
                                                                     uint32_t limit,
                                                                     EventsRecordField field,
                                                                     const char *str) override final;
    std::unique_ptr<std::vector<EventsRecord>> GetLimitOffsetByDate(uint32_t offset, uint32_t limit);

    std::unique_ptr<db::QueryResult> runQuery(std::shared_ptr<db::Query> query) override;



@@ 77,6 85,7 @@ class EventsRecordInterface : public RecordInterface<EventsRecord, EventsRecordF

    std::unique_ptr<db::query::events::GetResult> runQueryImpl(const db::query::events::Get *query);
    std::unique_ptr<db::query::events::GetAllResult> runQueryImpl(const db::query::events::GetAll *query);
    std::unique_ptr<db::query::events::GetAllLimitedResult> runQueryImpl(const db::query::events::GetAllLimited *query);
    std::unique_ptr<db::query::events::GetFilteredResult> runQueryImpl(const db::query::events::GetFiltered *query);
    std::unique_ptr<db::query::events::AddResult> runQueryImpl(const db::query::events::Add *query);
    std::unique_ptr<db::query::events::RemoveResult> runQueryImpl(const db::query::events::Remove *query);

M module-db/Tables/EventsTable.cpp => module-db/Tables/EventsTable.cpp +353 -42
@@ 1,5 1,7 @@
#include "EventsTable.hpp"
#include "module-db/Interface/EventsRecord.hpp"
//#include <module-apps/application-calendar/widgets/CalendarStyle.hpp>
//#include <module-apps/application-calendar/data/OptionParser.hpp>

#include <log/log.hpp>
#include <Utils.hpp>


@@ 20,16 22,303 @@ bool EventsTable::create()

bool EventsTable::add(EventsTableRow entry)
{
    return db->execute(
        "INSERT or IGNORE INTO events (title, description, date_from, date_till, reminder, repeat, time_zone) "
        "VALUES ('%q','%q', %lu, %lu, %lu, %lu, %lu);",
        entry.title.c_str(),
        entry.description.c_str(),
        entry.date_from,
        entry.date_till,
        entry.reminder,
        entry.repeat,
        entry.time_zone);
    // Prevent duplicates using ANDs:
    return db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) "
                       "SELECT '%q', '%q','%q', %lu, %lu "
                       "WHERE NOT EXISTS "
                       "(SELECT 1 FROM events e "
                       "WHERE e.title='%q' "
                       "AND e.date_from='%q' "
                       "AND e.date_till='%q' "
                       "AND e.reminder=%lu "
                       "AND e.repeat=%lu );",
                       entry.title.c_str(),
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat);
}

bool EventsTable::addDaily(EventsTableRow entry)
{
    return db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u);",
                       entry.title.c_str(),
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{1}).c_str(),
                       TimePointToString(entry.date_till + date::days{1}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{2}).c_str(),
                       TimePointToString(entry.date_till + date::days{2}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{3}).c_str(),
                       TimePointToString(entry.date_till + date::days{3}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{4}).c_str(),
                       TimePointToString(entry.date_till + date::days{4}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{5}).c_str(),
                       TimePointToString(entry.date_till + date::days{5}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{6}).c_str(),
                       TimePointToString(entry.date_till + date::days{6}).c_str(),
                       entry.reminder,
                       entry.repeat);
}

bool EventsTable::addWeekly(EventsTableRow entry)
{
    return db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u);",
                       entry.title.c_str(),
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{7}).c_str(),
                       TimePointToString(entry.date_till + date::days{7}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{14}).c_str(),
                       TimePointToString(entry.date_till + date::days{14}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{21}).c_str(),
                       TimePointToString(entry.date_till + date::days{21}).c_str(),
                       entry.reminder,
                       entry.repeat);
}

bool EventsTable::addTwoWeeks(EventsTableRow entry)
{
    return db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u);",
                       entry.title.c_str(),
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{14}).c_str(),
                       TimePointToString(entry.date_till + date::days{14}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{28}).c_str(),
                       TimePointToString(entry.date_till + date::days{28}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::days{42}).c_str(),
                       TimePointToString(entry.date_till + date::days{42}).c_str(),
                       entry.reminder,
                       entry.repeat);
}

bool EventsTable::addMonth(EventsTableRow entry)
{
    return db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u);",
                       entry.title.c_str(),
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{1}).c_str(),
                       TimePointToString(entry.date_till, date::months{1}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{2}).c_str(),
                       TimePointToString(entry.date_till, date::months{2}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{3}).c_str(),
                       TimePointToString(entry.date_till, date::months{3}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{4}).c_str(),
                       TimePointToString(entry.date_till, date::months{4}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{5}).c_str(),
                       TimePointToString(entry.date_till, date::months{5}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{6}).c_str(),
                       TimePointToString(entry.date_till, date::months{6}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{7}).c_str(),
                       TimePointToString(entry.date_till, date::months{7}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{8}).c_str(),
                       TimePointToString(entry.date_till, date::months{8}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{9}).c_str(),
                       TimePointToString(entry.date_till, date::months{9}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{10}).c_str(),
                       TimePointToString(entry.date_till, date::months{10}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{11}).c_str(),
                       TimePointToString(entry.date_till, date::months{11}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from, date::months{12}).c_str(),
                       TimePointToString(entry.date_till, date::months{12}).c_str(),
                       entry.reminder,
                       entry.repeat);
}

bool EventsTable::addYear(EventsTableRow entry)
{
    return db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u),"
                       "('%q', '%q','%q', %u, %u);",
                       entry.title.c_str(),
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::years{1}).c_str(),
                       TimePointToString(entry.date_till + date::years{1}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::years{2}).c_str(),
                       TimePointToString(entry.date_till + date::years{2}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::years{3}).c_str(),
                       TimePointToString(entry.date_till + date::years{3}).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.title.c_str(),
                       TimePointToString(entry.date_from + date::years{4}).c_str(),
                       TimePointToString(entry.date_till + date::years{4}).c_str(),
                       entry.reminder,
                       entry.repeat);
}

std::vector<bool> parseOptions(const uint32_t &dataDB)
{
    const uint32_t startBit        = 16;
    const uint32_t numberOfOptions = 7;
    std::vector<bool> weekDayOptions;
    for (uint32_t i = startBit; i < startBit + numberOfOptions; i++) {
        weekDayOptions.push_back(false);
    }
    for (uint32_t i = startBit; i < startBit + numberOfOptions; i++) {
        if (dataDB & (1 << i)) {
            LOG_DEBUG("SET OPTION ARRAY! %d", static_cast<int>(i));
            weekDayOptions[i - startBit] = true;
        }
    }
    return weekDayOptions;
}

std::string concatenate(const char *format, ...)
{
    std::string result = format;
    return result;
}

bool EventsTable::addCustom(EventsTableRow entry)
{
    // OptionParser parser;
    std::vector<bool> weekDayOptions;
    weekDayOptions = parseOptions(entry.repeat);

    std::string request = "INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES ";
    //    for (uint32_t i = 0; i < 7 ;i++)
    //    {
    //        if (weekDayOptions[i]){
    request = request + concatenate("('%q', datetime('%q',('+%u year')),datetime('%q',('+%u year')), %u, %u), ",
                                    entry.title.c_str(),
                                    TimePointToString(entry.date_from).c_str(),
                                    1,
                                    TimePointToString(entry.date_till).c_str(),
                                    1,
                                    entry.reminder,
                                    entry.repeat);

    request = request + concatenate("('%q', datetime('%q',('+%u day')),datetime('%q',('+%u day')), %u, %u); ",
                                    entry.title.c_str(),
                                    TimePointToString(entry.date_from).c_str(),
                                    2,
                                    TimePointToString(entry.date_till).c_str(),
                                    2,
                                    entry.reminder,
                                    entry.repeat);
    //        }
    //    }
    return db->execute(request.c_str());
}

bool EventsTable::removeById(uint32_t id)


@@ 57,15 346,13 @@ bool EventsTable::removeByField(EventsTableFields field, const char *str)

bool EventsTable::update(EventsTableRow entry)
{
    return db->execute("UPDATE events SET title= '%q', description = '%q', date_from = %u, date_till = %u, reminder "
                       "= %u, repeat = %u, time_zone = %u WHERE _id = %u;",
    return db->execute("UPDATE events SET title= '%q', date_from = '%q', date_till = '%q', reminder "
                       "= %u, repeat = %u WHERE _id = %u;",
                       entry.title.c_str(),
                       entry.description.c_str(),
                       entry.date_from,
                       entry.date_till,
                       TimePointToString(entry.date_from).c_str(),
                       TimePointToString(entry.date_till).c_str(),
                       entry.reminder,
                       entry.repeat,
                       entry.time_zone,
                       entry.ID);
}



@@ 80,21 367,22 @@ EventsTableRow EventsTable::getById(uint32_t id)
    assert(retQuery->getRowCount() == 1);

    return EventsTableRow{
        (*retQuery)[0].getUInt32(), // ID
        (*retQuery)[1].getString(), // title
        (*retQuery)[2].getString(), // description
        (*retQuery)[3].getUInt32(), // date_from
        (*retQuery)[4].getUInt32(), // date_till
        (*retQuery)[5].getUInt32(), // reminder
        (*retQuery)[6].getUInt32(), // repeat
        (*retQuery)[7].getUInt32()  // time_zone
        (*retQuery)[0].getUInt32(),                              // ID
        (*retQuery)[1].getString(),                              // title
        TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
        TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
        (*retQuery)[4].getUInt32(),                              // reminder
        (*retQuery)[5].getUInt32()                               // repeat

    };
}

std::vector<EventsTableRow> EventsTable::selectByDatePeriod(uint32_t date_from, uint32_t date_till)
std::vector<EventsTableRow> EventsTable::selectByDatePeriod(TimePoint date_filter, TimePoint filter_till)
{
    auto retQuery = db->query("SELECT * FROM events WHERE date_from >= %u AND date_till <= %u;", date_from, date_till);
    auto retQuery =
        db->query("SELECT * FROM events WHERE date_from >= date('%q') AND date_till < date('%q', 'start of day');",
                  TimePointToString(date_filter).c_str(),
                  TimePointToString(filter_till).c_str());

    if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
        return std::vector<EventsTableRow>();


@@ 104,15 392,14 @@ std::vector<EventsTableRow> EventsTable::selectByDatePeriod(uint32_t date_from, 

    do {
        ret.push_back(EventsTableRow{
            (*retQuery)[0].getUInt32(), // ID
            (*retQuery)[1].getString(), // title
            (*retQuery)[2].getString(), // description
            (*retQuery)[3].getUInt32(), // date_from
            (*retQuery)[4].getUInt32(), // date_till
            (*retQuery)[5].getUInt32(), // reminder
            (*retQuery)[6].getUInt32(), // repeat
            (*retQuery)[7].getUInt32()  // time_zone
            (*retQuery)[0].getUInt32(),                              // ID
            (*retQuery)[1].getString(),                              // title
            TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
            TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
            (*retQuery)[4].getUInt32(),                              // reminder
            (*retQuery)[5].getUInt32()                               // repeat
        });

    } while (retQuery->nextRow());

    return ret;


@@ 131,14 418,38 @@ std::vector<EventsTableRow> EventsTable::getLimitOffset(uint32_t offset, uint32_

    do {
        ret.push_back(EventsTableRow{
            (*retQuery)[0].getUInt32(), // ID
            (*retQuery)[1].getString(), // title
            (*retQuery)[2].getString(), // description
            (*retQuery)[3].getUInt32(), // date_from
            (*retQuery)[4].getUInt32(), // date_till
            (*retQuery)[5].getUInt32(), // reminder
            (*retQuery)[6].getUInt32(), // repeat
            (*retQuery)[7].getUInt32()  // time_zone
            (*retQuery)[0].getUInt32(),                              // ID
            (*retQuery)[1].getString(),                              // title
            TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
            TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
            (*retQuery)[4].getUInt32(),                              // reminder
            (*retQuery)[5].getUInt32()                               // repeat

        });
    } while (retQuery->nextRow());

    return ret;
}

std::vector<EventsTableRow> EventsTable::getLimitOffsetByDate(uint32_t offset, uint32_t limit)
{

    auto retQuery = db->query("SELECT * from events ORDER BY datetime(date_from) LIMIT %u OFFSET %u;", limit, offset);

    if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
        return std::vector<EventsTableRow>();
    }

    std::vector<EventsTableRow> ret;

    do {
        ret.push_back(EventsTableRow{
            (*retQuery)[0].getUInt32(),                              // ID
            (*retQuery)[1].getString(),                              // title
            TimePointFromString((*retQuery)[2].getString().c_str()), // date_from
            TimePointFromString((*retQuery)[3].getString().c_str()), // date_till
            (*retQuery)[4].getUInt32(),                              // reminder
            (*retQuery)[5].getUInt32()                               // repeat
        });
    } while (retQuery->nextRow());


M module-db/Tables/EventsTable.hpp => module-db/Tables/EventsTable.hpp +15 -10
@@ 5,16 5,15 @@
#include <Database/Database.hpp>
#include <Common/Common.hpp>
#include <utf8/UTF8.hpp>
#include <module-apps/application-calendar/data/dateCommon.hpp>

struct EventsTableRow : public Record
{
    std::string title;
    std::string description;
    uint32_t date_from = 0;
    uint32_t date_till = 0;
    TimePoint date_from = TIME_POINT_INVALID;
    TimePoint date_till = TIME_POINT_INVALID;
    uint32_t reminder  = 0;
    uint32_t repeat    = 0;
    uint32_t time_zone = 0;
};

enum class EventsTableFields


@@ 31,11 30,17 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>

    bool create() override final;
    bool add(EventsTableRow entry) override final;
    bool addDaily(EventsTableRow entry);
    bool addWeekly(EventsTableRow entry);
    bool addTwoWeeks(EventsTableRow entry);
    bool addMonth(EventsTableRow entry);
    bool addYear(EventsTableRow entry);
    bool addCustom(EventsTableRow entry);
    bool removeById(uint32_t id) override final;
    bool removeByField(EventsTableFields field, const char *str) override final;
    bool update(EventsTableRow entry) override final;
    EventsTableRow getById(uint32_t id) override final;
    std::vector<EventsTableRow> selectByDatePeriod(uint32_t date_from, uint32_t date_till);
    std::vector<EventsTableRow> selectByDatePeriod(TimePoint filter_from, TimePoint filter_till);
    uint32_t count() override final;
    uint32_t countByFieldId(const char *field, uint32_t id) override final;
    std::vector<EventsTableRow> getLimitOffset(uint32_t offset, uint32_t limit) override final;


@@ 44,14 49,14 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
                                                      EventsTableFields field,
                                                      const char *str) override final;

    std::vector<EventsTableRow> getLimitOffsetByDate(uint32_t offset, uint32_t limit);

  private:
    const char *createTableQuery = "CREATE TABLE IF NOT EXISTS events("
                                   "_id INTEGER PRIMARY KEY AUTOINCREMENT,"
                                   "title TEXT,"
                                   "description TEXT,"
                                   "date_from INTEGER,"
                                   "date_till INTEGER,"
                                   "date_from DATETIME,"
                                   "date_till DATETIME,"
                                   "reminder INTEGER,"
                                   "repeat INTEGER,"
                                   "time_zone INTEGER);";
                                   "repeat INTEGER);";
};

M module-db/queries/calendar/QueryEventsEdit.cpp => module-db/queries/calendar/QueryEventsEdit.cpp +1 -7
@@ 2,8 2,7 @@

namespace db::query::events
{
    Edit::Edit(EventsRecord record, const uint32_t &dateFrom)
        : Query(Query::Type::Update), record(record), dateFrom(dateFrom)
    Edit::Edit(EventsRecord record) : Query(Query::Type::Update), record(record)
    {}

    auto Edit::getRecord() const -> EventsRecord


@@ 11,11 10,6 @@ namespace db::query::events
        return record;
    }

    auto Edit::getDateFrom() const -> uint32_t
    {
        return dateFrom;
    }

    auto Edit::debugInfo() const -> std::string
    {
        return "Edit";

M module-db/queries/calendar/QueryEventsEdit.hpp => module-db/queries/calendar/QueryEventsEdit.hpp +1 -4
@@ 9,13 9,10 @@ namespace db::query::events
    class Edit : public Query
    {
        EventsRecord record;
        /// Check value
        uint32_t dateFrom;

      public:
        Edit(EventsRecord record, const uint32_t &dateFrom);
        Edit(EventsRecord record);

        [[nodiscard]] auto getDateFrom() const -> uint32_t;
        [[nodiscard]] auto getRecord() const -> EventsRecord;
        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

A module-db/queries/calendar/QueryEventsGetAllLimited.cpp => module-db/queries/calendar/QueryEventsGetAllLimited.cpp +32 -0
@@ 0,0 1,32 @@
#include "QueryEventsGetAllLimited.hpp"

namespace db::query::events
{
    GetAllLimited::GetAllLimited(const uint32_t &offset, const uint32_t &limit)
        : Query(Query::Type::Read), offset(offset), limit(limit)
    {}

    auto GetAllLimited::debugInfo() const -> std::string
    {
        return "GetAllLimited";
    }

    GetAllLimitedResult::GetAllLimitedResult(std::unique_ptr<std::vector<EventsRecord>> records,
                                             std::unique_ptr<uint32_t> count)
        : records(std::move(records)), recordsCount(std::move(count))
    {}

    auto GetAllLimitedResult::getResult() -> std::unique_ptr<std::vector<EventsRecord>>
    {
        return std::move(records);
    }
    auto GetAllLimitedResult::getCountResult() -> std::unique_ptr<uint32_t>
    {
        return std::move(recordsCount);
    }

    auto GetAllLimitedResult::debugInfo() const -> std::string
    {
        return "GetAllLimitedResult";
    }
} // namespace db::query::events

A module-db/queries/calendar/QueryEventsGetAllLimited.hpp => module-db/queries/calendar/QueryEventsGetAllLimited.hpp +32 -0
@@ 0,0 1,32 @@
#pragma once

#include <module-db/Interface/EventsRecord.hpp>
#include <Common/Query.hpp>
#include <string>

namespace db::query::events
{
    class GetAllLimited : public Query
    {
      public:
        GetAllLimited(const uint32_t &offset, const uint32_t &limit);
        [[nodiscard]] auto debugInfo() const -> std::string override;

        uint32_t offset = 0;
        uint32_t limit  = 0;
    };

    class GetAllLimitedResult : public QueryResult
    {
        std::unique_ptr<std::vector<EventsRecord>> records;
        std::unique_ptr<uint32_t> recordsCount;

      public:
        GetAllLimitedResult(std::unique_ptr<std::vector<EventsRecord>> records, std::unique_ptr<uint32_t> count);
        [[nodiscard]] auto getResult() -> std::unique_ptr<std::vector<EventsRecord>>;
        [[nodiscard]] auto getCountResult() -> std::unique_ptr<uint32_t>;

        [[nodiscard]] auto debugInfo() const -> std::string override;
    };

} // namespace db::query::events

M module-db/queries/calendar/QueryEventsGetFiltered.cpp => module-db/queries/calendar/QueryEventsGetFiltered.cpp +2 -2
@@ 2,8 2,8 @@

namespace db::query::events
{
    GetFiltered::GetFiltered(const uint32_t &date_from, const uint32_t &date_till)
        : Query(Query::Type::Read), date_from(date_from), date_till(date_till)
    GetFiltered::GetFiltered(TimePoint filter_from, TimePoint filter_till)
        : Query(Query::Type::Read), filter_from(filter_from), filter_till(filter_till)
    {}

    auto GetFiltered::debugInfo() const -> std::string

M module-db/queries/calendar/QueryEventsGetFiltered.hpp => module-db/queries/calendar/QueryEventsGetFiltered.hpp +4 -3
@@ 3,17 3,18 @@
#include "module-db/Interface/EventsRecord.hpp"
#include <Common/Query.hpp>
#include <string>
#include <module-apps/application-calendar/data/dateCommon.hpp>

namespace db::query::events
{
    class GetFiltered : public Query
    {
      public:
        GetFiltered(const uint32_t &date_from, const uint32_t &date_till);
        GetFiltered(TimePoint filter_from, TimePoint filter_till);
        [[nodiscard]] auto debugInfo() const -> std::string override;

        uint32_t date_from;
        uint32_t date_till;
        TimePoint filter_from;
        TimePoint filter_till;
    };

    class GetFilteredResult : public QueryResult

M module-db/queries/calendar/QueryEventsRemove.cpp => module-db/queries/calendar/QueryEventsRemove.cpp +1 -1
@@ 2,7 2,7 @@

namespace db::query::events
{
    Remove::Remove(const uint32_t &id) : Query(Query::Type::Delete)
    Remove::Remove(const uint32_t &id) : Query(Query::Type::Delete), id(id)
    {}

    auto Remove::debugInfo() const -> std::string

M module-db/tests/EventsRecord_tests.cpp => module-db/tests/EventsRecord_tests.cpp +104 -117
@@ 5,6 5,7 @@
#include "Databases/EventsDB.hpp"
#include "module-db/queries/calendar/QueryEventsGet.hpp"
#include "module-db/queries/calendar/QueryEventsGetAll.hpp"
#include "module-db/queries/calendar/QueryEventsGetAllLimited.hpp"
#include "module-db/queries/calendar/QueryEventsGetFiltered.hpp"
#include "module-db/queries/calendar/QueryEventsAdd.hpp"
#include "module-db/queries/calendar/QueryEventsRemove.hpp"


@@ 32,25 33,24 @@ TEST_CASE("Events Record tests")
    {
        EventsRecord testRec;
        REQUIRE(testRec.title == "");
        REQUIRE(testRec.description == "");
        REQUIRE(testRec.date_from == 0);
        REQUIRE(testRec.date_till == 0);
        REQUIRE(testRec.reminder == 0);
        REQUIRE(testRec.repeat == 0);
        REQUIRE(testRec.time_zone == 0);
    }

    SECTION("Constructor from EventsTableRow")
    {
        EventsTableRow tableRow{{.ID = 10}, "Event3", "Desc3", 1910201424, 1910201536, 1, 2, 1};
        EventsTableRow tableRow{{.ID = 10},
                                "Event3",
                                TimePointFromString("2019-10-20 14:24"),
                                TimePointFromString("2019-10-20 15:36"),
                                1,
                                2};
        EventsRecord testRec(tableRow);
        REQUIRE(testRec.title == "Event3");
        REQUIRE(testRec.description == "Desc3");
        REQUIRE(testRec.date_from == 1910201424);
        REQUIRE(testRec.date_till == 1910201536);
        REQUIRE(testRec.date_from == TimePointFromString("2019-10-20 14:24"));
        REQUIRE(testRec.date_till == TimePointFromString("2019-10-20 15:36"));
        REQUIRE(testRec.reminder == 1);
        REQUIRE(testRec.repeat == 2);
        REQUIRE(testRec.time_zone == 1);
        REQUIRE(testRec.isValid());
    }



@@ 60,33 60,30 @@ TEST_CASE("Events Record tests")
    auto numberOfEvents = eventsRecordInterface.GetCount();
    REQUIRE(numberOfEvents == 0);

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

    REQUIRE(eventsRecordInterface.Add(rec));

    numberOfEvents = eventsRecordInterface.GetCount();
    REQUIRE(numberOfEvents == 1);
    REQUIRE(numberOfEvents == 4);

    SECTION("Get entry by ID")
    {
        auto entry = eventsRecordInterface.GetByID(1);
        REQUIRE(entry.ID == 1);
        REQUIRE(entry.title == "Event1");
        REQUIRE(entry.description == "Desc1");
        REQUIRE(entry.date_from == 1910201424);
        REQUIRE(entry.date_till == 1910201536);
        REQUIRE(entry.date_from == TimePointFromString("2019-10-20 14:24"));
        REQUIRE(entry.date_till == TimePointFromString("2019-10-20 15:36"));
        REQUIRE(entry.reminder == 1);
        REQUIRE(entry.repeat == 2);
        REQUIRE(entry.time_zone == 1);
        REQUIRE(entry.isValid());
    }



@@ 95,30 92,27 @@ TEST_CASE("Events Record tests")
        auto entry = eventsRecordInterface.GetByID(100);
        REQUIRE(entry.ID == DB_ID_NONE);
        REQUIRE(entry.title == "");
        REQUIRE(entry.description == "");
        REQUIRE(entry.date_from == 0);
        REQUIRE(entry.date_till == 0);
        REQUIRE(entry.date_from == TIME_POINT_INVALID);
        REQUIRE(entry.date_till == TIME_POINT_INVALID);
        REQUIRE(entry.reminder == 0);
        REQUIRE(entry.repeat == 0);
        REQUIRE(entry.time_zone == 0);
        REQUIRE_FALSE(entry.isValid());
    }

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

    REQUIRE(eventsRecordInterface.Add(rec2));

    numberOfEvents = eventsRecordInterface.GetCount();
    REQUIRE(numberOfEvents == 2);
    REQUIRE(numberOfEvents == 8);

    SECTION("Get entries")
    {


@@ 138,7 132,7 @@ TEST_CASE("Events Record tests")
        SECTION("Get table rows using invalid offset/limit parameters(should return empty object)")
        {
            auto retOffsetLimit = eventsRecordInterface.GetLimitOffset(5, 4);
            REQUIRE(retOffsetLimit->size() == 0);
            REQUIRE(retOffsetLimit->size() == 3);
        }

        SECTION("0 - get all")


@@ 147,107 141,89 @@ TEST_CASE("Events Record tests")
            REQUIRE(retOffsetLimit->size() == numberOfEvents);
        }

        SECTION("Get table rows by SELECT")
        SECTION("Get table rows by SELECT invalid")
        {
            auto retOffsetLimit = eventsRecordInterface.Select(1810201424, 1911201536);
            REQUIRE(retOffsetLimit->size() == 1);
            auto entry = retOffsetLimit->back();
            REQUIRE(entry.ID == 1);
            REQUIRE(entry.title == "Event1");
            REQUIRE(entry.description == "Desc1");
            REQUIRE(entry.date_from == 1910201424);
            REQUIRE(entry.date_till == 1910201536);
            REQUIRE(entry.reminder == 1);
            REQUIRE(entry.repeat == 2);
            REQUIRE(entry.time_zone == 1);
            REQUIRE(entry.isValid());
            auto retOffsetLimit = eventsRecordInterface.Select(TimePointFromString("2010-10-20 14:24"),
                                                               TimePointFromString("2010-10-20 15:36"));
            REQUIRE(retOffsetLimit->size() == 0);
        }
    }

    SECTION("Entry update value")
    {
        auto entryPre        = eventsRecordInterface.GetByID(1);
        auto checkV          = entryPre.date_from;
        entryPre.title       = "newTitle";
        entryPre.description = "newDesc";
        entryPre.date_from   = 1999999999;
        entryPre.date_till   = 1999999999;
        LOG_DEBUG("LOG ON!!!!!!!!!!!!!!!!!!");
        REQUIRE(eventsRecordInterface.Update(entryPre, checkV));
        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");
        REQUIRE(eventsRecordInterface.Update(entryPre));

        auto entry = eventsRecordInterface.GetByID(1);
        REQUIRE(entry.ID == entryPre.ID);
        REQUIRE(entry.title == entryPre.title);
        REQUIRE(entry.description == entryPre.description);
        REQUIRE(entry.date_from == entryPre.date_from);
        REQUIRE(entry.date_till == entryPre.date_till);
        REQUIRE(entry.reminder == entryPre.reminder);
        REQUIRE(entry.repeat == entryPre.repeat);
        REQUIRE(entry.time_zone == entryPre.time_zone);
    }

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

    REQUIRE(eventsRecordInterface.Add(rec3));

    numberOfEvents = eventsRecordInterface.GetCount();
    REQUIRE(numberOfEvents == 3);

    auto getQuery =
        [&](uint32_t id, std::string title, std::string description, uint32_t date_from, uint32_t date_till) {
            auto query  = std::make_shared<db::query::events::Get>(id);
            auto ret    = eventsRecordInterface.runQuery(query);
            auto result = dynamic_cast<db::query::events::GetResult *>(ret.get());
            REQUIRE(result != nullptr);
            auto record = result->getResult();
            REQUIRE(record.isValid());
            REQUIRE(record.title == title);
            REQUIRE(record.description == description);
            REQUIRE(record.date_from == date_from);
            REQUIRE(record.date_till == date_till);

            return record.date_from;
        };
    auto getQuery = [&](uint32_t id, std::string title, TimePoint date_from, TimePoint date_till) {
        auto query  = std::make_shared<db::query::events::Get>(id);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::GetResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto record = result->getResult();
        REQUIRE(record.isValid());
        REQUIRE(record.title == title);

        return record.date_from;
    };

    auto getFiltered = [&](uint32_t id,
                           std::string title,
                           std::string description,
                           uint32_t date_from,
                           uint32_t date_till,
                           uint32_t filter_from,
                           uint32_t filter_till) {
                           TimePoint date_from,
                           TimePoint date_till,
                           TimePoint filter_from,
                           TimePoint filter_till) {
        auto query  = std::make_shared<db::query::events::GetFiltered>(filter_from, filter_till);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::GetFilteredResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto records = result->getResult();
        auto record  = records->back();
        REQUIRE(record.isValid());
        REQUIRE(record.title == title);
        REQUIRE(record.description == description);
        REQUIRE(record.date_from == date_from);
        REQUIRE(record.date_till == date_till);
        REQUIRE(records->size() == 0);
    };

    auto getAllLimited = [&](uint32_t offset, uint32_t limit) {
        auto query  = std::make_shared<db::query::events::GetAllLimited>(offset, limit);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::GetAllLimitedResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto records = result->getResult();
        REQUIRE(records->size() == limit);
        auto count = result->getCountResult();
        return count;
    };

    auto AddQuery =
        [&](uint32_t id, std::string title, std::string description, uint32_t date_from, uint32_t date_till) {
            EventsTableRow tableRow2{{.ID = id}, title, description, date_from, date_till, 1, 2, 1};
            auto record = EventsRecord(tableRow2);
            auto query  = std::make_shared<db::query::events::Add>(record);
            auto ret    = eventsRecordInterface.runQuery(query);
            auto result = dynamic_cast<db::query::events::AddResult *>(ret.get());
            REQUIRE(result != nullptr);
            REQUIRE(result->getResult());
        };
    auto AddQuery = [&](uint32_t id, std::string title, TimePoint date_from, TimePoint date_till) {
        EventsTableRow tableRow2{{.ID = id}, title, date_from, date_till, 1, 2};
        auto record = EventsRecord(tableRow2);
        auto query  = std::make_shared<db::query::events::Add>(record);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::AddResult *>(ret.get());
        REQUIRE(result != nullptr);
        REQUIRE(result->getResult());
    };

    auto RemoveQuery = [&](uint32_t id) {
        auto query  = std::make_shared<db::query::events::Remove>(id);


@@ 259,16 235,13 @@ TEST_CASE("Events Record tests")

    auto EditQuery = [&](uint32_t id,
                         std::string title,
                         std::string description,
                         uint32_t date_from,
                         uint32_t date_till,
                         TimePoint date_from,
                         TimePoint date_till,
                         uint32_t reminder,
                         uint32_t repeat,
                         uint32_t time_zone,
                         uint32_t checkV) {
        EventsTableRow tableRow2{{.ID = id}, title, description, date_from, date_till, reminder, repeat, time_zone};
                         uint32_t repeat) {
        EventsTableRow tableRow2{{.ID = id}, title, date_from, date_till, reminder, repeat};
        auto record = EventsRecord(tableRow2);
        auto query  = std::make_shared<db::query::events::Edit>(record, checkV);
        auto query  = std::make_shared<db::query::events::Edit>(record);
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::EditResult *>(ret.get());
        REQUIRE(result != nullptr);


@@ 281,28 254,29 @@ TEST_CASE("Events Record tests")
        auto recordGet = resultGet->getResult();
        REQUIRE(recordGet.isValid());
        REQUIRE(recordGet.title == title);
        REQUIRE(recordGet.description == description);
        REQUIRE(recordGet.date_from == date_from);
        REQUIRE(recordGet.date_till == date_till);
        REQUIRE(recordGet.reminder == reminder);
        REQUIRE(recordGet.repeat == repeat);
        REQUIRE(recordGet.time_zone == time_zone);
    };

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

    SECTION("GetFiltered via query")
    {
        getFiltered(1, "Event1", "Desc1", 1910201424, 1910201536, 1810201424, 1912201536);
        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"));
    }

    SECTION("Add via query")
    {
        AddQuery(3, "Event3", "Desc3", 2610201424, 2210201536);
        getQuery(4, "Event3", "Desc3", 2610201424, 2210201536);
        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"));
    }

    SECTION("Remove via query")


@@ 313,13 287,12 @@ TEST_CASE("Events Record tests")
        auto result = dynamic_cast<db::query::events::GetAllResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto records = result->getResult();
        REQUIRE(records->size() == 3);
        REQUIRE(records->size() == 11);
    }

    SECTION("Update via query")
    {
        uint32_t checkV = getQuery(2, "Event2", "Desc2", 2510201424, 2510201536);
        EditQuery(2, "Event3", "Desc2", 2110201424, 2110201536, 1, 2, 2, checkV);
        EditQuery(2, "Event3", TimePointFromString("2021-10-20 14:24"), TimePointFromString("2021-10-20 15:36"), 1, 2);
    }

    SECTION("Get All via query")


@@ 329,7 302,21 @@ TEST_CASE("Events Record tests")
        auto result = dynamic_cast<db::query::events::GetAllResult *>(ret.get());
        REQUIRE(result != nullptr);
        auto records = result->getResult();
        REQUIRE(records->size() == 3);
        REQUIRE(records->size() == 12);
    }

    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"));
        auto count1     = getAllLimited(0, 2);
        auto count2     = getAllLimited(2, 5);
        auto &eventsTbl = eventsDb.events;
        auto count3     = eventsTbl.count();
        REQUIRE(*count1 == *count2);
        REQUIRE(*count2 == count3);
    }

    Database::deinitialize();

M module-db/tests/EventsTable_tests.cpp => module-db/tests/EventsTable_tests.cpp +136 -92
@@ 28,31 28,25 @@ TEST_CASE("Events Table tests")
        EventsTableRow testRow;
        REQUIRE(testRow.ID == DB_ID_NONE);
        REQUIRE(testRow.title == "");
        REQUIRE(testRow.description == "");
        REQUIRE(testRow.date_from == 0);
        REQUIRE(testRow.date_till == 0);
        REQUIRE(testRow.date_from == TIME_POINT_INVALID);
        REQUIRE(testRow.date_till == TIME_POINT_INVALID);
        REQUIRE(testRow.reminder == 0);
        REQUIRE(testRow.repeat == 0);
        REQUIRE(testRow.time_zone == 0);
        REQUIRE_FALSE(testRow.isValid());
    }

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

    REQUIRE(eventsTbl.count() == 2);



@@ 61,12 55,10 @@ TEST_CASE("Events Table tests")
        auto entry = eventsTbl.getById(2);
        REQUIRE(entry.ID == 2);
        REQUIRE(entry.title == "Event4");
        REQUIRE(entry.description == "Desc4");
        REQUIRE(entry.date_from == 2104191224);
        REQUIRE(entry.date_till == 2104201536);
        REQUIRE(entry.date_from == TimePointFromString("2021-10-20 12:24"));
        REQUIRE(entry.date_till == TimePointFromString("2021-10-20 15:36"));
        REQUIRE(entry.reminder == 0);
        REQUIRE(entry.repeat == 3);
        REQUIRE(entry.time_zone == 0);
        REQUIRE(entry.isValid());
    }



@@ 79,95 71,147 @@ TEST_CASE("Events Table tests")
        auto entry = eventsTbl.getById(1);
        REQUIRE(entry.ID == 1);
        REQUIRE(entry.title == "Event3");
        REQUIRE(entry.description == "Desc3");
        REQUIRE(entry.date_from == 1910201424);
        REQUIRE(entry.date_till == 1910201536);
        REQUIRE(entry.date_from == TimePointFromString("2019-10-20 14:24"));
        REQUIRE(entry.date_till == TimePointFromString("2019-10-20 15:36"));
        REQUIRE(entry.reminder == 1);
        REQUIRE(entry.repeat == 2);
        REQUIRE(entry.time_zone == 1);
        REQUIRE(entry.isValid());
    }

    SECTION("Update entry by ID")
    {
        auto entry =
            EventsTableRow({{.ID = 2}, "TestUpdateEvent", "Tested update event", 1910201500, 1910201854, 0, 2, 1});
        auto entry = EventsTableRow({{.ID = 2},
                                     "TestUpdateEvent",
                                     TimePointFromString("2019-10-20 15:00"),
                                     TimePointFromString("2019-10-20 18:54"),
                                     0,
                                     2});
        REQUIRE(eventsTbl.update(entry));
        auto record = eventsTbl.getById(2);
        REQUIRE(record.ID == 2);
        REQUIRE(record.title == "TestUpdateEvent");
        REQUIRE(record.description == "Tested update event");
        REQUIRE(record.date_from == 1910201500);
        REQUIRE(record.date_till == 1910201854);
        REQUIRE(record.date_from == TimePointFromString("2019-10-20 15:00"));
        REQUIRE(record.date_till == TimePointFromString("2019-10-20 18:54"));
        REQUIRE(record.reminder == 0);
        REQUIRE(record.repeat == 2);
        REQUIRE(record.time_zone == 1);
        REQUIRE(record.isValid());
    }

    SECTION("Select entry by date")
    {
        REQUIRE(eventsTbl.add({{.ID = 0},
                               .title       = "Event5",
                               .description = "Desc5",
                               .date_from   = 1910201424,
                               .date_till   = 1910201536,
                               .reminder    = 1,
                               .repeat      = 2,
                               .time_zone   = 1}));
        REQUIRE(eventsTbl.add({{.ID = 0},
                               .title       = "Event6",
                               .description = "Desc6",
                               .date_from   = 2104191224,
                               .date_till   = 2104201536,
                               .reminder    = 0,
                               .repeat      = 3,
                               .time_zone   = 0}));
        REQUIRE(eventsTbl.add({{.ID = 0},
                               .title       = "Event7",
                               .description = "Desc7",
                               .date_from   = 1910201524,
                               .date_till   = 1910201536,
                               .reminder    = 1,
                               .repeat      = 2,
                               .time_zone   = 1}));
        REQUIRE(eventsTbl.add({{.ID = 0},
                               .title       = "Event8",
                               .description = "Desc8",
                               .date_from   = 1504191224,
                               .date_till   = 1504201536,
                               .reminder    = 0,
                               .repeat      = 3,
                               .time_zone   = 0}));
        REQUIRE(eventsTbl.add({{.ID = 0},
                               .title       = "Event9",
                               .description = "Desc9",
                               .date_from   = 2510201424,
                               .date_till   = 2510201536,
                               .reminder    = 1,
                               .repeat      = 2,
                               .time_zone   = 1}));
        REQUIRE(eventsTbl.add({{.ID = 0},
                               .title       = "Event10",
                               .description = "Desc10",
                               .date_from   = 2112191224,
                               .date_till   = 2112201536,
                               .reminder    = 0,
                               .repeat      = 3,
                               .time_zone   = 0}));

        auto entries = eventsTbl.selectByDatePeriod(1910201500, 2104201500);
        auto entry   = entries.back();
        REQUIRE(entry.ID == 5);
        REQUIRE(entry.title == "Event7");
        REQUIRE(entry.description == "Desc7");
        REQUIRE(entry.date_from == 1910201524);
        REQUIRE(entry.date_till == 1910201536);
        REQUIRE(entry.reminder == 1);
        REQUIRE(entry.repeat == 2);
        REQUIRE(entry.time_zone == 1);
        REQUIRE(entry.isValid());
                               .title     = "Event5",
                               .date_from = TimePointFromString("2019-10-20 14:24"),
                               .date_till = TimePointFromString("2019-10-20 15:36"),
                               .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"),
                               .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"),
                               .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"),
                               .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"),
                               .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"),
                               .reminder  = 0,
                               .repeat    = 3}));

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

        REQUIRE(entries.size() == 0);
    }
    for (uint32_t i = 1; i <= 8; ++i) {
        auto response = eventsTbl.removeById(i);
        REQUIRE(response);
    }
    REQUIRE(eventsTbl.count() == 0);
    SECTION("Get all limited by date")
    {
        for (uint32_t i = 1; i <= 3; ++i) {
            auto response = eventsTbl.removeById(i);
            REQUIRE(response);
        }
        REQUIRE(eventsTbl.count() == 0);

        const std::array<TimePoint, 6> paramDate{TimePointFromString("2018-10-20 15:24"),
                                                 TimePointFromString("2019-10-30 14:24"),
                                                 TimePointFromString("2020-10-20 14:24"),
                                                 TimePointFromString("2021-12-20 14:24"),
                                                 TimePointFromString("2022-10-20 14:24"),
                                                 TimePointFromString("2023-10-20 14:24")};
        const std::array<uint32_t, 6> paramID{3, 4, 5, 6, 7, 8};
        const std::array<std::string, 6> paramName{"Event1", "Event2", "Event3", "Event4", "Event5", "Event6"};
        REQUIRE(eventsTbl.add({{.ID = 1},
                               .title     = "Event1",
                               .date_from = paramDate[0],
                               .date_till = TimePointFromString("2030-10-20 15:24"),
                               .reminder  = 0,
                               .repeat    = 0}));
        REQUIRE(eventsTbl.add({{.ID = 2},
                               .title     = "Event2",
                               .date_from = paramDate[5],
                               .date_till = TimePointFromString("2030-10-20 15:24"),
                               .reminder  = 0,
                               .repeat    = 0}));
        REQUIRE(eventsTbl.add({{.ID = 3},
                               .title     = "Event3",
                               .date_from = paramDate[2],
                               .date_till = TimePointFromString("2030-10-20 15:24"),
                               .reminder  = 0,
                               .repeat    = 0}));
        REQUIRE(eventsTbl.add({{.ID = 4},
                               .title     = "Event4",
                               .date_from = paramDate[3],
                               .date_till = TimePointFromString("2030-10-20 15:24"),
                               .reminder  = 0,
                               .repeat    = 0}));
        REQUIRE(eventsTbl.add({{.ID = 5},
                               .title     = "Event5",
                               .date_from = paramDate[4],
                               .date_till = TimePointFromString("2030-10-20 15:24"),
                               .reminder  = 0,
                               .repeat    = 0}));
        REQUIRE(eventsTbl.add({{.ID = 6},
                               .title     = "Event6",
                               .date_from = paramDate[1],
                               .date_till = TimePointFromString("2030-10-20 15:24"),
                               .reminder  = 0,
                               .repeat    = 0}));

        auto entries = eventsTbl.getLimitOffsetByDate(0, 6);
        REQUIRE(entries.size() == 6);
        uint32_t index = 0;
        for (auto entry : entries) {
            REQUIRE(entry.ID == paramID[index]);
            REQUIRE(entry.title == paramName[index]);
            REQUIRE(entry.date_from == paramDate[index]);
            REQUIRE(entry.date_till == TimePointFromString("2030-10-20 15:24"));
            REQUIRE(entry.reminder == 0);
            REQUIRE(entry.repeat == 0);
            REQUIRE(entry.isValid());
            ++index;
        }
    }

    Database::deinitialize();
}

M module-gui/gui/widgets/CheckBox.cpp => module-gui/gui/widgets/CheckBox.cpp +1 -1
@@ 20,7 20,7 @@ namespace gui
        setEdges(RectangleEdgeFlags::GUI_RECT_EDGE_BOTTOM);
        setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center));

        image = new Image("small_tick");
        image = new Image("small_tick_W_M");
        image->setVisible(false);
        addWidget(image);


M module-utils/time/time_locale.hpp => module-utils/time/time_locale.hpp +10 -0
@@ 144,6 144,16 @@ namespace utils
                }
                return localize.get(tlocale.time_formats[what]);
            }

            static const UTF8 getAM()
            {
                return localize.get("common_AM");
            }

            static const UTF8 getPM()
            {
                return localize.get("common_PM");
            }
        };

    }; // namespace time