Rework mirai core

This commit is contained in:
Vyn 2024-10-11 16:26:13 +02:00
parent f885d355cd
commit 36a2fe9220
62 changed files with 27689 additions and 765 deletions

View file

@ -7,9 +7,9 @@
#include "UiState.h"
#include "Utils.h"
#include "appwindow.h"
#include "mirai-core/Day.h"
#include "mirai-core/Mirai.h"
#include "mirai-core/TaskItem.h"
#include "mirai-core/TodoMd.h"
#include "mirai-core/SourceDataProvider.h"
#include "slint.h"
#include "slint_sharedvector.h"
#include "slint_string.h"
@ -46,16 +46,11 @@ UiState::UiState(mirai::Mirai *miraiInstance) : miraiInstance_(miraiInstance), v
);
mainWindow_->global<Backend>().set_sources(sourcesNames);
taskWindow_->global<Backend>().set_sources_selected(sources_);
taskWindow_->global<Backend>().set_sources(sourcesNames);
taskWindow_->global<Backend>().set_tags(tags_);
eventWindow_->global<Backend>().set_sources_selected(sources_);
eventWindow_->global<Backend>().set_tags(tags_);
view_.setAllSources();
view_.update();
reloadSources();
reloadTags();
reloadTasks();
setupCallbacks();
@ -82,147 +77,6 @@ std::optional<Date> stringToDate(const std::string &dateStr)
return Date{.year = year, .month = month, .day = day};
}
void UiState::setupTaskWindowCallbacks()
{
mainWindow_->global<Backend>().on_saveTask([&](SaveTaskData newTaskData) {
auto source = miraiInstance_->getSourceById(newTaskData.sourceId);
assert(source);
auto task = source->getTaskById(newTaskData.id);
assert(task);
const Date &date = newTaskData.date;
const std::string dateStr = SlintDateToStdString(date);
auto taskData =
mirai::TodoMdFormat::stringToTask("- [ ] " + std::string(newTaskData.title), dateStr);
task->setText(taskData.text);
if (task->day() && task->day()->getDate() != SlintDateToMiraiDate(date)) {
auto newDate = source->day(SlintDateToMiraiDate(date));
newDate->createTask({
.text = taskData.text,
.state = task->getState(),
.tags = taskData.tags,
});
auto oldDate = task->day();
source->deleteTask(*task);
}
miraiInstance_->save();
view_.update();
reloadTasks();
taskWindow_->hide();
});
mainWindow_->global<Backend>().on_createTask([&](NewTaskData newTaskData) {
const Date &date = newTaskData.date;
const std::string dateStr = SlintDateToStdString(date);
auto source = miraiInstance_->getSourceById(newTaskData.sourceId);
auto task =
mirai::TodoMdFormat::stringToTask("- [ ] " + std::string(newTaskData.title), dateStr);
if (!newTaskData.scheduled) {
source->addUnscheduledTask(task);
} else if (newTaskData.eventId == -1) {
auto day = source->day(SlintDateToMiraiDate(date));
assert(day);
day->createTask(task);
} else {
auto event = source->getEventById(newTaskData.eventId);
assert(event);
event->createTask(task);
}
miraiInstance_->save();
view_.update();
reloadTasks();
taskWindow_->hide();
});
}
void UiState::setupEventWindowCallbacks()
{
mainWindow_->global<Backend>().on_open_new_event_form([&]() {
auto todayDate = std::chrono::year_month_day{
std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())
};
eventWindow_->set_eventId(-1);
eventWindow_->set_taskTitle("");
eventWindow_->set_taskDate({
.year = static_cast<int>(todayDate.year()),
// Try to directly use `unsigned`
.month = static_cast<int>(static_cast<unsigned>(todayDate.month())),
.day = static_cast<int>(static_cast<unsigned>(todayDate.day())),
});
eventWindow_->show();
});
mainWindow_->global<Backend>().on_open_edit_event_form([&](int sourceId, int eventId) {
auto source = miraiInstance_->getSourceById(sourceId);
assert(source);
auto event = source->getEventById(eventId);
assert(event);
eventWindow_->global<Backend>().set_sources_selected(sources_);
eventWindow_->global<Backend>().set_tags(tags_);
eventWindow_->set_sourceId(sourceId);
eventWindow_->set_eventId(eventId);
eventWindow_->set_taskTitle(slint::SharedString(event->getText()));
eventWindow_->set_taskDate(MiraiDateToSlintDate(event->getDate()));
eventWindow_->set_startsAt(MiraiTimeToSlintTime(event->getStartTime()));
eventWindow_->set_endsAt(MiraiTimeToSlintTime(event->getEndTime()));
eventWindow_->show();
});
mainWindow_->global<Backend>().on_delete_event_clicked([&](int sourceId, int eventId) {
auto source = miraiInstance_->getSourceById(sourceId);
assert(source);
auto event = source->getEventById(eventId);
assert(event);
auto day = event->day();
assert(day);
day->deleteEvent(*event);
miraiInstance_->save();
view_.update();
reloadTasks();
});
mainWindow_->global<Backend>().on_createEvent([&](NewEventParams newEventParams) {
const Date &date = newEventParams.date;
const std::string dateStr = SlintDateToStdString(date);
auto source = miraiInstance_->getSourceById(newEventParams.sourceId);
auto day = source->day(SlintDateToMiraiDate(date));
day->createEvent({
.description = std::string(newEventParams.title),
.date = SlintDateToMiraiDate(newEventParams.date),
.startTime = SlintTimeToMiraiTime(newEventParams.startsAt),
.endTime = SlintTimeToMiraiTime(newEventParams.endsAt),
});
miraiInstance_->save();
view_.update();
reloadTasks();
eventWindow_->hide();
});
mainWindow_->global<Backend>().on_saveEvent([&](SaveEventParams newEventParams) {
const Date &date = newEventParams.date;
const std::string dateStr = SlintDateToStdString(date);
auto source = miraiInstance_->getSourceById(newEventParams.sourceId);
assert(source);
auto event = source->getEventById(newEventParams.id);
assert(event);
event->setText(std::string(newEventParams.title));
event->setStartTime(SlintTimeToMiraiTime(newEventParams.startsAt));
event->setEndTime(SlintTimeToMiraiTime(newEventParams.endsAt));
// TODO we can't change the date of the event for now.
miraiInstance_->save();
view_.update();
reloadTasks();
eventWindow_->hide();
});
}
void UiState::setupUtilsCallbacks()
{
mainWindow_->global<Backend>().on_formatDate([&](const Date &date) {
@ -242,108 +96,48 @@ void UiState::setupCallbacks()
assert(source);
auto task = source->getTaskById(taskId);
assert(task);
task->getState() == mirai::DONE ? task->markAsUndone() : task->markAsDone();
task->setChecked(!task->checked());
// task->getState() == mirai::DONE ? task->markAsUndone() : task->markAsDone();
miraiInstance_->save();
});
mainWindow_->global<Backend>().on_source_clicked([&](int index) {
// index with value -1 is equal to no selection, aka "All"
if (index == -1) {
view_.removeFilters();
view_.setAllSources();
} else {
view_.removeFilters();
const auto &source = miraiInstance_->getSourceById(index);
const auto &sourceName = source->getName();
view_.addSourceFilter(sourceName);
/*
// Old behavior, I keep it here for now
const auto &source = miraiInstance_->getSourceById(index);
const auto &sourceName = source->getName();
if (std::ranges::find(view_.getActiveFilesFilter(), sourceName) ==
view_.getActiveFilesFilter().end()) {
view_.addSourceFilter(sourceName);
} else {
view_.removeSourceFilter(sourceName);
}
*/
view_.removeSources();
const mirai::Source *source = miraiInstance_->getSourceById(index);
view_.addSource(*source);
}
view_.update();
reloadSources();
reloadTasks();
});
mainWindow_->global<Backend>().on_tag_clicked([&](int index) {
const std::string &tag = miraiInstance_->getTags().at(index);
if (std::ranges::find(view_.getActiveTagsFilter(), tag) ==
view_.getActiveTagsFilter().end()) {
view_.addTagFilter(tag);
} else {
view_.removeTagFilter(tag);
}
view_.update();
reloadTasks();
});
/*mainWindow_->global<Backend>().on_tag_clicked([&](int index) {*/
/*const std::string &tag = miraiInstance_->getTags().at(index);*/
/*if (std::ranges::find(view_.getActiveTagsFilter(), tag) ==*/
/*view_.getActiveTagsFilter().end()) {*/
/*view_.addTagFilter(tag);*/
/*} else {*/
/*view_.removeTagFilter(tag);*/
/*}*/
/*view_.update();*/
/*reloadTasks();*/
/*});*/
mainWindow_->global<Backend>().on_delete_task_clicked([&](int sourceId, int taskId) {
auto source = miraiInstance_->getSourceById(sourceId);
assert(source);
auto task = source->getTaskById(taskId);
assert(task);
source->deleteTask(*task);
source->removeTask(*task);
miraiInstance_->save();
view_.update();
reloadTasks();
});
mainWindow_->global<Backend>().on_open_edit_task_form([&](int sourceId, int taskId) {
auto source = miraiInstance_->getSourceById(sourceId);
assert(source);
auto task = source->getTaskById(taskId);
assert(task);
taskWindow_->set_taskSourceIndex(sourceId);
taskWindow_->set_taskId(task->id());
taskWindow_->set_taskTitle(slint::SharedString(task->getText()));
if (task->day() != nullptr) {
taskWindow_->set_scheduled(true);
taskWindow_->set_taskDate(MiraiDateToSlintDate(task->day()->getDate()));
} else {
taskWindow_->set_scheduled(false);
}
taskWindow_->show();
});
mainWindow_->global<Backend>().on_open_new_task_form([&](OpenNewTaskFormParams params) {
taskWindow_->global<Backend>().set_sources_selected(sources_);
taskWindow_->global<Backend>().set_tags(tags_);
auto todayDate = std::chrono::year_month_day{
std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())
};
taskWindow_->set_taskId(-1);
taskWindow_->set_eventId(params.eventId);
taskWindow_->set_taskSourceIndex(params.eventSourceId == -1 ? 0 : params.eventSourceId);
taskWindow_->set_taskTitle("");
if (params.eventId == -1) {
taskWindow_->set_taskDate({
.year = static_cast<int>(todayDate.year()),
// Try to directly use `unsigned`
.month = static_cast<int>(static_cast<unsigned>(todayDate.month())),
.day = static_cast<int>(static_cast<unsigned>(todayDate.day())),
});
} else {
auto source = miraiInstance_->getSourceById(params.eventSourceId);
assert(source);
auto event = source->getEventById(params.eventId);
assert(event);
taskWindow_->set_taskDate(MiraiDateToSlintDate(event->getDate()));
}
taskWindow_->show();
});
mainWindow_->global<Backend>().on_toggle_show_completed_tasks([&] {
view_.hideCompletedTasks(!view_.shouldHideCompletedTasks());
view_.update();
@ -354,8 +148,95 @@ void UiState::setupCallbacks()
mainWindow_->global<Backend>().set_tags(tags_);
mainWindow_->global<Backend>().set_visible_tasks(days_);
setupTaskWindowCallbacks();
setupEventWindowCallbacks();
mainWindow_->global<Backend>().on_saveTask([&](SaveTaskData newTaskData) {
auto source = miraiInstance_->getSourceById(newTaskData.sourceId);
assert(source);
auto task = source->getTaskById(newTaskData.id);
assert(task);
const mirai::Date &date = SlintDateToMiraiDate(newTaskData.date);
const auto dayOpt = source->getDayByDate(date);
if (!dayOpt.has_value()) {
throw std::runtime_error("Missing auto day creation implementation");
}
const auto day = dayOpt.value();
task->setTitle(std::string(newTaskData.title));
task->setDay(day);
miraiInstance_->save();
view_.update();
reloadTasks();
});
mainWindow_->global<Backend>().on_createTask([&](NewTaskData newTaskData) {
std::optional<mirai::Date> date = std::nullopt;
if (newTaskData.date.year != 0) {
date = SlintDateToMiraiDate(newTaskData.date);
}
auto source = miraiInstance_->getSourceById(newTaskData.sourceId);
std::optional<mirai::Event> event = std::nullopt;
if (newTaskData.eventId >= 0) {
event = source->getEventById(newTaskData.eventId);
}
source->createTask({
.title = std::string(newTaskData.title),
.event = event,
.date = date,
});
miraiInstance_->save();
view_.update();
reloadTasks();
});
mainWindow_->global<Backend>().on_delete_event_clicked([&](int sourceId, int eventId) {
auto source = miraiInstance_->getSourceById(sourceId);
assert(source);
auto event = source->getEventById(eventId);
assert(event.has_value());
source->removeEvent(event.value());
miraiInstance_->save();
view_.update();
reloadTasks();
});
mainWindow_->global<Backend>().on_createEvent([&](NewEventParams newEventParams) {
const Date &date = newEventParams.date;
const std::string dateStr = SlintDateToStdString(date);
auto source = miraiInstance_->getSourceById(newEventParams.sourceId);
source->createEvent({
.title = std::string(newEventParams.title),
.date = SlintDateToMiraiDate(newEventParams.date),
.startsAt = SlintTimeToMiraiTime(newEventParams.startsAt),
.endsAt = SlintTimeToMiraiTime(newEventParams.endsAt),
});
miraiInstance_->save();
view_.update();
reloadTasks();
});
mainWindow_->global<Backend>().on_saveEvent([&](SaveEventParams newEventParams) {
const Date &date = newEventParams.date;
const std::string dateStr = SlintDateToStdString(date);
auto source = miraiInstance_->getSourceById(newEventParams.sourceId);
assert(source);
auto event = source->getEventById(newEventParams.id);
assert(event);
event->setTitle(std::string(newEventParams.title));
event->setStartTime(SlintTimeToMiraiTime(newEventParams.startsAt));
event->setEndTime(SlintTimeToMiraiTime(newEventParams.endsAt));
// TODO we can't change the date of the event for now.
miraiInstance_->save();
view_.update();
reloadTasks();
});
setupUtilsCallbacks();
}
@ -376,70 +257,58 @@ void UiState::reloadTasks()
return;
}
auto todayDate = mirai::Date(std::chrono::system_clock::now());
auto &days = view_;
auto dates = view_.getDates();
auto slintDays = std::make_shared<slint::VectorModel<Day>>();
for (int dayIndex = 0; dayIndex < days.count(); ++dayIndex) {
auto &currentDay = view_[dayIndex];
for (int dayIndex = 0; dayIndex < dates.size(); ++dayIndex) {
auto &currentDate = dates.at(dayIndex);
auto slintEvents = std::make_shared<slint::VectorModel<Event>>();
auto slintDayTasks = std::make_shared<slint::VectorModel<TaskData>>();
auto relativeDaysDiff = std::chrono::duration_cast<std::chrono::days>(
std::chrono::sys_days(currentDay.day->getDate().toStdChrono()) -
std::chrono::sys_days(currentDate.toStdChrono()) -
std::chrono::sys_days(todayDate.toStdChrono())
)
.count();
slintDays->push_back(
Day{.sourceId = currentDay.day->source()->id(),
.id = dayIndex,
.date = MiraiDateToSlintDate(currentDay.day->getDate()),
Day{.date = MiraiDateToSlintDate(currentDate),
.events = slintEvents,
.tasks = slintDayTasks,
.isLate = currentDay.day->getDate() < todayDate,
.isToday = currentDay.day->getDate() == todayDate,
.isLate = currentDate < todayDate,
.isToday = currentDate == todayDate,
.relativeDaysDiff = static_cast<int>(relativeDaysDiff)}
);
for (int taskIndex = 0; taskIndex < currentDay.filteredTasks.size(); ++taskIndex) {
auto &task = currentDay.filteredTasks.at(taskIndex);
std::vector<slint::SharedString> tags;
std::transform(
task->getTags().begin(), task->getTags().end(), std::back_inserter(tags),
[&](const std::string &tag) {
return slint::SharedString(tag);
}
);
// Day's tasks
const std::vector<mirai::Task> tasksForDate = view_.getTasksForDate(currentDate);
for (int taskIndex = 0; taskIndex < tasksForDate.size(); ++taskIndex) {
auto &task = tasksForDate.at(taskIndex);
slintDayTasks->push_back({
.sourceId = task->source()->id(),
.id = task->id(),
.title = slint::SharedString(task->getText()),
.checked = task->getState() == mirai::DONE,
.tags = std::make_shared<slint::VectorModel<slint::SharedString>>(tags),
.sourceId = task.sourceId(),
.id = task.id(),
.title = slint::SharedString(task.title()),
.checked = task.checked(),
});
}
for (int eventIndex = 0; eventIndex < currentDay.filteredEvents.size(); ++eventIndex) {
auto &currentEvent = currentDay.filteredEvents.at(eventIndex);
// Day's events
const std::vector<mirai::Event> eventsForDate = view_.getEventsForDate(currentDate);
for (int eventIndex = 0; eventIndex < eventsForDate.size(); ++eventIndex) {
auto &currentEvent = eventsForDate.at(eventIndex);
auto slintTasks = std::make_shared<slint::VectorModel<TaskData>>();
slintEvents->push_back(Event{
.sourceId = currentEvent.event->day()->source()->id(),
.id = currentEvent.event->id(),
.title = slint::SharedString(currentEvent.event->getText()),
.startsAt = MiraiTimeToSlintTime(currentEvent.event->getStartTime()),
.endsAt = MiraiTimeToSlintTime(currentEvent.event->getEndTime()),
.sourceId = currentEvent.sourceId(),
.id = currentEvent.id(),
.title = slint::SharedString(currentEvent.title()),
.startsAt = MiraiTimeToSlintTime(currentEvent.startsAt()),
.endsAt = MiraiTimeToSlintTime(currentEvent.endsAt()),
.tasks = slintTasks,
});
for (int taskIndex = 0; taskIndex < currentEvent.filteredTasks.size(); ++taskIndex) {
auto &task = currentEvent.filteredTasks.at(taskIndex);
std::vector<slint::SharedString> tags;
std::transform(
task->getTags().begin(), task->getTags().end(), std::back_inserter(tags),
[&](const std::string &tag) {
return slint::SharedString(tag);
}
);
auto eventTasks = currentEvent.queryTasks();
for (int taskIndex = 0; taskIndex < eventTasks.size(); ++taskIndex) {
auto &task = eventTasks.at(taskIndex);
slintTasks->push_back({
.sourceId = task->source()->id(),
.id = task->id(),
.title = slint::SharedString(task->getText()),
.checked = task->getState() == mirai::DONE,
.tags = std::make_shared<slint::VectorModel<slint::SharedString>>(tags),
.sourceId = task.sourceId(),
.id = task.id(),
.title = slint::SharedString(task.title()),
.checked = task.checked(),
});
}
}
@ -447,22 +316,15 @@ void UiState::reloadTasks()
days_ = slintDays;
mainWindow_->global<Backend>().set_visible_tasks(days_);
auto unscheduledTasksView = view_.getUnscheduledTasks();
unscheduledTasks_->clear();
for (int taskIndex = 0; taskIndex < view_.filteredUnscheduledTasks().size(); ++taskIndex) {
auto &task = view_.filteredUnscheduledTasks().at(taskIndex);
std::vector<slint::SharedString> tags;
std::transform(
task->getTags().begin(), task->getTags().end(), std::back_inserter(tags),
[&](const std::string &tag) {
return slint::SharedString(tag);
}
);
for (int taskIndex = 0; taskIndex < unscheduledTasksView.size(); ++taskIndex) {
auto &task = unscheduledTasksView.at(taskIndex);
unscheduledTasks_->push_back({
.sourceId = task->source()->id(),
.id = task->id(),
.title = slint::SharedString(task->getText()),
.checked = task->getState() == mirai::DONE,
.tags = std::make_shared<slint::VectorModel<slint::SharedString>>(tags),
.sourceId = task.sourceId(),
.id = task.id(),
.title = slint::SharedString(task.title()),
.checked = task.checked(),
});
}
mainWindow_->global<Backend>().set_unscheduled_tasks(unscheduledTasks_);
@ -471,27 +333,17 @@ void UiState::reloadTasks()
void UiState::reloadSources()
{
sources_->clear();
bool noSourceSelected = true;
bool noSourceSelected = miraiInstance_->getSources().size() == view_.activeSourceCount();
for (const auto &source : miraiInstance_->getSources()) {
bool isSourceSelected = view_.isSourceFilterActive(source->getName());
bool isSourceSelected = view_.isSourceSelected(*source);
sources_->push_back(
{.name = slint::SharedString(source->getName()), .selected = isSourceSelected}
{.name = slint::SharedString(source->name()),
.selected = isSourceSelected && !noSourceSelected}
);
if (isSourceSelected) {
noSourceSelected = false;
}
}
mainWindow_->global<Backend>().set_no_source_selected(noSourceSelected);
}
void UiState::reloadTags()
{
tags_->clear();
for (const auto &tag : miraiInstance_->getTags()) {
tags_->push_back(slint::SharedString(tag));
}
}
void UiState::run()
{
mainWindow_->run();

View file

@ -8,7 +8,7 @@
#include "appwindow.h"
#include "mirai-core/Mirai.h"
#include "mirai-core/TasksView.h"
#include "mirai-core/View.h"
#include "slint.h"
class UiState
@ -20,13 +20,10 @@ class UiState
void run();
void reloadSources();
void reloadTags();
void reloadTasks();
private:
void setupCallbacks();
void setupTaskWindowCallbacks();
void setupEventWindowCallbacks();
void setupUtilsCallbacks();
std::shared_ptr<slint::VectorModel<Source>> sources_;
@ -35,9 +32,7 @@ class UiState
std::shared_ptr<slint::VectorModel<TaskData>> unscheduledTasks_;
slint::ComponentHandle<AppWindow> mainWindow_ = AppWindow::create();
slint::ComponentHandle<TaskWindow> taskWindow_ = TaskWindow::create();
slint::ComponentHandle<EventWindow> eventWindow_ = EventWindow::create();
mirai::Mirai *miraiInstance_;
mirai::TasksView view_;
mirai::View view_;
};

View file

@ -6,9 +6,12 @@
#include "UiState.h"
#include "mirai-core/Config.h"
#include "mirai-core/MarkdownDataProvider.h"
#include "mirai-core/Mirai.h"
#include "mirai-core/StdFileSource.h"
#include "mirai-core/SourceDataProvider.h"
#include <algorithm>
#include <cstdlib>
#include <memory>
#include <string>
int main(int argc, char **argv)
@ -18,9 +21,8 @@ int main(int argc, char **argv)
mirai::Mirai mirai;
for (const auto &sourceFilePath : config.sources()) {
auto file = std::make_unique<mirai::StdFileSource>(
mirai::BaseFileSourceConstructor{.name = sourceFilePath, .path = sourceFilePath}
);
std::unique_ptr<mirai::SourceDataProvider> file =
std::make_unique<mirai::MarkdownDataProvider>(sourceFilePath);
mirai.loadSource(std::move(file));
}