~aleteoryx/muditaos

4942167c0a410a504edde0347e2484fbd3b9bc10 — Tomas Rogala 5 years ago 07b243a
[EGD-3713] Rework repeat option data flow

-Implement onIsChecked callbacks
-Add Custom repeat functionality
-Prevent from repeated events duplicates
M changelog.md => changelog.md +1 -0
@@ 11,6 11,7 @@

### Changed

* `[calendar]` Fixed custom repeat option.
* `[antenna-app]` Added parameter history window.
* `[phonenumber]` Change default country to unknown.


M module-apps/application-calendar/data/CalendarData.cpp => module-apps/application-calendar/data/CalendarData.cpp +10 -2
@@ 8,7 8,7 @@ WeekDaysRepeatData::WeekDaysRepeatData()
    }
}

[[nodiscard]] auto WeekDaysRepeatData::getData(const uint32_t &weekDay) const -> bool
[[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));


@@ 17,7 17,7 @@ WeekDaysRepeatData::WeekDaysRepeatData()
    return weekDays[weekDay];
}

void WeekDaysRepeatData::setData(const uint32_t &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));


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

M module-apps/application-calendar/data/CalendarData.hpp => module-apps/application-calendar/data/CalendarData.hpp +3 -2
@@ 39,8 39,9 @@ class WeekDaysRepeatData : public gui::SwitchData
  public:
    WeekDaysRepeatData();
    virtual ~WeekDaysRepeatData() = default;
    [[nodiscard]] auto getData(const uint32_t &weekDay) const -> bool;
    virtual void setData(const uint32_t &weekDay);
    [[nodiscard]] auto getData(const uint32_t weekDay) const -> bool;
    virtual void setData(const uint32_t weekDay, const bool value);
    virtual void setData(const uint32_t weekDay);
};

class DayMonthData : public gui::SwitchData

M module-apps/application-calendar/data/dateCommon.hpp => module-apps/application-calendar/data/dateCommon.hpp +10 -0
@@ 97,6 97,16 @@ inline std::string TimePointToString(const TimePoint &tp)
    return date::format("%F %T", time_point_cast<seconds>(tp));
}

inline TimePoint getFirstWeekDay(const TimePoint &tp)
{
    date::year_month_day yearMonthDay = date::year_month_day{date::floor<date::days>(tp)};
    while (date::weekday{yearMonthDay} != date::mon) {
        auto decrementedDay = --yearMonthDay.day();
        yearMonthDay        = yearMonthDay.year() / yearMonthDay.month() / decrementedDay;
    }
    return date::sys_days{yearMonthDay.year() / yearMonthDay.month() / yearMonthDay.day()};
}

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

M module-apps/application-calendar/models/CustomRepeatModel.cpp => module-apps/application-calendar/models/CustomRepeatModel.cpp +15 -0
@@ 58,3 58,18 @@ void CustomRepeatModel::loadData(const std::shared_ptr<WeekDaysRepeatData> &data

    list->rebuildList();
}

std::vector<bool> CustomRepeatModel::getIsCheckedData()
{
    std::vector<bool> isCheckedData;
    for (auto item : internalData) {
        if (item->onContentChangeCallback && item->onContentChangeCallback()) {
            isCheckedData.push_back(true);
        }
        else {
            isCheckedData.push_back(false);
        }
    }

    return isCheckedData;
}

M module-apps/application-calendar/models/CustomRepeatModel.hpp => module-apps/application-calendar/models/CustomRepeatModel.hpp +1 -5
@@ 19,11 19,7 @@ class CustomRepeatModel : public app::InternalModel<gui::CalendarListItem *>, pu
    [[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;
    }
    std::vector<bool> getIsCheckedData();

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

M module-apps/application-calendar/widgets/CalendarListItem.hpp => module-apps/application-calendar/widgets/CalendarListItem.hpp +1 -0
@@ 9,6 9,7 @@ namespace gui
      public:
        std::function<void(std::shared_ptr<EventsRecord> event)> onSaveCallback = nullptr;
        std::function<void(std::shared_ptr<EventsRecord> event)> onLoadCallback = nullptr;
        std::function<bool()> onContentChangeCallback                           = nullptr;
    };

} /* namespace gui */

M module-apps/application-calendar/widgets/CheckBoxWithLabelItem.cpp => module-apps/application-calendar/widgets/CheckBoxWithLabelItem.cpp +2 -0
@@ 68,6 68,7 @@ namespace gui
        if (checkBoxData != nullptr) {
            setCheckBoxes();
        }
        onContentChangeCallback = [&]() { return checkBox->isChecked(); };
    }

    void CheckBoxWithLabelItem::applyCallbacks()


@@ 87,6 88,7 @@ namespace gui
        inputCallback = [&](gui::Item &item, const gui::InputEvent &event) {
            if (checkBox->onInput(event)) {
                checkBox->resizeItems();
                onContentChangeCallback = [&]() { return checkBox->isChecked(); };
                return true;
            }
            return false;

M module-apps/application-calendar/windows/CustomRepeatWindow.cpp => module-apps/application-calendar/windows/CustomRepeatWindow.cpp +3 -6
@@ 67,13 67,10 @@ namespace gui
        switch (inputEvent.keyCode) {
        case KeyCode::KEY_RF: {
            if (weekDaysOptData != nullptr) {
                auto items = customRepeatModel->getInternalData();
                auto isCheckedData = customRepeatModel->getIsCheckedData();
                uint32_t i = 0;
                for (auto it : items) {
                    auto item = dynamic_cast<CheckBoxWithLabelItem *>(it);
                    if (item && item->checkBox->isChecked()) {
                        weekDaysOptData->setData(i);
                    }
                for (auto checked : isCheckedData) {
                    weekDaysOptData->setData(i, checked);
                    ++i;
                }
                auto data = weekDaysOptData.get();

M module-apps/application-calendar/windows/NewEditEventWindow.cpp => module-apps/application-calendar/windows/NewEditEventWindow.cpp +2 -2
@@ 62,9 62,9 @@ namespace gui
        if (mode == ShowMode::GUI_SHOW_RETURN) {
            auto receivedData = dynamic_cast<WeekDaysRepeatData *>(data);
            if (receivedData != nullptr) {
                auto parser         = new OptionParser();
                auto parser         = std::make_unique<OptionParser>();
                auto uniqueData     = std::make_unique<WeekDaysRepeatData>(*receivedData);
                eventRecord->repeat = eventRecord->repeat + parser->getDatabaseFieldValue(std::move(uniqueData));
                eventRecord->repeat = parser->getDatabaseFieldValue(std::move(uniqueData));
                newEditEventModel->loadRepeat(eventRecord);
            }
        }

M module-db/Interface/EventsRecord.cpp => module-db/Interface/EventsRecord.cpp +2 -6
@@ 49,12 49,10 @@ bool EventsRecordInterface::Add(const EventsRecord &rec)
        return eventsDb->events.addYear(entry);
    }
    default: {
        break;
        eventsDb->events.addCustom(entry);
        return eventsDb->events.addCustom(entry);
    }
    }

    return true;
}

std::unique_ptr<std::vector<EventsRecord>> EventsRecordInterface::Select(TimePoint filter_from, TimePoint filter_till)


@@ 151,11 149,9 @@ bool EventsRecordInterface::Update(const EventsRecord &rec)
        return (eventsDb->events.addYear(entry) && result);
    }
    default: {
        break;
        eventsDb->events.addCustom(entry);
        return eventsDb->events.addCustom(entry);
    }
    }
    return false;
}

bool EventsRecordInterface::RemoveByID(uint32_t id)

M module-db/Tables/EventsTable.cpp => module-db/Tables/EventsTable.cpp +28 -33
@@ 276,49 276,44 @@ std::vector<bool> parseOptions(const uint32_t &dataDB)
    }
    for (uint32_t i = startBit; i < startBit + numberOfOptions; i++) {
        if (dataDB & (1 << i)) {
            LOG_DEBUG("SET OPTION ARRAY! %d", static_cast<int>(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;
    const uint32_t numberOfWeeks    = 4;
    const uint32_t numberOfWeekDays = 7;
    bool result                     = true;
    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());
    weekDayOptions          = parseOptions(entry.repeat);
    uint32_t incrementation = 0;

    auto dateFrom = getFirstWeekDay(entry.date_from);
    auto dateTill = getFirstWeekDay(entry.date_till);

    for (uint32_t i = 1; i <= numberOfWeeks; i++) {
        for (auto option : weekDayOptions) {
            if (option) {
                result =
                    result &&
                    db->execute("INSERT or IGNORE INTO events (title, date_from, date_till, reminder, repeat) VALUES"
                                "('%q', '%q','%q', %u, %u);",
                                entry.title.c_str(),
                                TimePointToString(dateFrom + date::days{incrementation}).c_str(),
                                TimePointToString(dateTill + date::days{incrementation}).c_str(),
                                entry.reminder,
                                entry.repeat);
            }
            ++incrementation;
        }
        incrementation = i * numberOfWeekDays;
    }
    return result;
}

bool EventsTable::removeById(uint32_t id)

M module-db/Tables/EventsTable.hpp => module-db/Tables/EventsTable.hpp +4 -3
@@ 12,8 12,8 @@ struct EventsTableRow : public Record
    std::string title;
    TimePoint date_from = TIME_POINT_INVALID;
    TimePoint date_till = TIME_POINT_INVALID;
    uint32_t reminder  = 0;
    uint32_t repeat    = 0;
    uint32_t reminder   = 0;
    uint32_t repeat     = 0;
};

enum class EventsTableFields


@@ 58,5 58,6 @@ class EventsTable : public Table<EventsTableRow, EventsTableFields>
                                   "date_from DATETIME,"
                                   "date_till DATETIME,"
                                   "reminder INTEGER,"
                                   "repeat INTEGER);";
                                   "repeat INTEGER,"
                                   "UNIQUE (title, date_from, date_till));";
};

M module-db/tests/EventsRecord_tests.cpp => module-db/tests/EventsRecord_tests.cpp +1 -2
@@ 245,7 245,6 @@ TEST_CASE("Events Record tests")
        auto ret    = eventsRecordInterface.runQuery(query);
        auto result = dynamic_cast<db::query::events::EditResult *>(ret.get());
        REQUIRE(result != nullptr);
        REQUIRE(result->getResult());

        auto queryGet  = std::make_shared<db::query::events::Get>(id);
        auto retGet    = eventsRecordInterface.runQuery(queryGet);


@@ 292,7 291,7 @@ TEST_CASE("Events Record tests")

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

    SECTION("Get All via query")