From 4bca7fac3ed49e8887c3c99a1c96a142018a77fe Mon Sep 17 00:00:00 2001 From: Vyn Date: Thu, 26 Jun 2025 10:12:23 +0200 Subject: [PATCH] Add color for events and source tags --- .../mirai-core/include/mirai-core/Mirai.h | 3 +- .../mirai-core/include/mirai-core/Source.h | 7 +++- external/mirai-core/src/Mirai.cpp | 13 ++++--- external/mirai-core/src/Source.cpp | 13 +++++-- external/selenite | 2 +- src/components/Calendar.slint | 35 +++++++------------ src/components/TaskLine.slint | 4 ++- src/modals/EditSourceModal.slint | 8 ++++- src/shared/Actions.slint | 4 +-- src/shared/Models.slint | 22 +++++++++++- src/windows/AppWindow/AppWindow.cpp | 21 +++++++++-- src/windows/AppWindow/views/TasksView.slint | 2 ++ 12 files changed, 95 insertions(+), 39 deletions(-) diff --git a/external/mirai-core/include/mirai-core/Mirai.h b/external/mirai-core/include/mirai-core/Mirai.h index 2a8d9b8..b0a39e7 100644 --- a/external/mirai-core/include/mirai-core/Mirai.h +++ b/external/mirai-core/include/mirai-core/Mirai.h @@ -24,7 +24,8 @@ class Mirai void addSource( const std::string &name, const std::string &type, std::unique_ptr &&source ); - void editSource(int id, const std::string &name, const std::string &path); + void + editSource(int id, const std::string &name, const std::string &color, const std::string &path); void deleteSource(int id); void unloadAllSources(); void save(); diff --git a/external/mirai-core/include/mirai-core/Source.h b/external/mirai-core/include/mirai-core/Source.h index a6e8bf8..3a32b4c 100644 --- a/external/mirai-core/include/mirai-core/Source.h +++ b/external/mirai-core/include/mirai-core/Source.h @@ -32,6 +32,7 @@ struct createEventParams { struct SourceConstructor { std::string name; + std::string color; DataProvider *sourceDataProvider; }; @@ -39,7 +40,8 @@ class Source { public: Source(SourceConstructor params) - : data(params.sourceDataProvider), name_(params.name), type_("FileSystemMarkdown") + : data(params.sourceDataProvider), name_(params.name), color_(params.color), + type_("FileSystemMarkdown") { } @@ -56,9 +58,11 @@ class Source std::string name() const; std::string type() const; + std::string color() const; DataProvider *dataProvider(); void setName(const std::string &name); + void setColor(const std::string &color); void createTask(const createTaskParams &task); void removeTask(const Task &task); @@ -92,6 +96,7 @@ class Source std::string name_; std::string type_; + std::string color_; DataProvider *data; }; } // namespace mirai diff --git a/external/mirai-core/src/Mirai.cpp b/external/mirai-core/src/Mirai.cpp index 36ff6c9..5f7683a 100644 --- a/external/mirai-core/src/Mirai.cpp +++ b/external/mirai-core/src/Mirai.cpp @@ -41,14 +41,15 @@ void Mirai::loadConfig(const std::string &path) auto &filePath = jsonSources[i]; assert(filePath.isObject()); const auto name = filePath.asObject().getString("name"); + const auto color = filePath.asObject().getString("color"); const auto path = filePath.asObject().getString("path"); std::unique_ptr file = std::make_unique(path); DataProvider *sourceDataProvider = file.release(); sourceDataProvider->load(); sources_.push_back( - std::make_unique( - SourceConstructor{.name = name, .sourceDataProvider = sourceDataProvider} - ) + std::make_unique(SourceConstructor{ + .name = name, .color = color, .sourceDataProvider = sourceDataProvider + }) ); } } @@ -67,6 +68,7 @@ void Mirai::saveConfig() rei::json::JsonObject jsonSource; jsonSource.set("name", source->name()); + jsonSource.set("color", source->color()); auto dataProvider = dynamic_cast(source->dataProvider()); jsonSource.set("path", dataProvider->path()); jsonSource.set("type", "FileSystemMarkdown"); @@ -96,10 +98,13 @@ void Mirai::addSource( sourceAdded.emit(nullptr); }; -void Mirai::editSource(int id, const std::string &name, const std::string &path) +void Mirai::editSource( + int id, const std::string &name, const std::string &color, const std::string &path +) { auto source = getSourceById(id); source->setName(name); + source->setColor(color); DataProvider *sourceDataProvider = source->dataProvider(); saveConfig(); diff --git a/external/mirai-core/src/Source.cpp b/external/mirai-core/src/Source.cpp index bf3dac2..9ced168 100644 --- a/external/mirai-core/src/Source.cpp +++ b/external/mirai-core/src/Source.cpp @@ -52,8 +52,7 @@ std::vector Source::getDays() auto daysData = data->getDays(); std::vector days; std::transform( - daysData.begin(), daysData.end(), std::back_inserter(days), - [&](const DayData &dayData) { + daysData.begin(), daysData.end(), std::back_inserter(days), [&](const DayData &dayData) { return Day{data, dayData}; } ); @@ -148,11 +147,21 @@ std::string Source::name() const return name_; } +std::string Source::color() const +{ + return color_; +} + void Source::setName(const std::string &name) { name_ = name; } +void Source::setColor(const std::string &color) +{ + color_ = color; +} + std::string Source::type() const { // There is only 1 type for now diff --git a/external/selenite b/external/selenite index 9592f1b..0fa6be0 160000 --- a/external/selenite +++ b/external/selenite @@ -1 +1 @@ -Subproject commit 9592f1b18d149e1cf76a32df419f6ed3db2af3d6 +Subproject commit 0fa6be0b1abe9534a8a1252496b7c97219c1559e diff --git a/src/components/Calendar.slint b/src/components/Calendar.slint index 2f75357..4eb1404 100644 --- a/src/components/Calendar.slint +++ b/src/components/Calendar.slint @@ -1,25 +1,7 @@ import { ScrollView, Date, Time } from "std-widgets.slint"; import { VCheckBox, VButton, VActionButton, Svg, VTag, VPopupIconMenu, VText, Palette } from "@selenite"; import { Utils } from "../shared/Utils.slint"; - -export struct CalendarDayEvent { - sourceId: int, - id: int, - title: string, - startsAt: Time, - endsAt: Time -} - -export struct CalendarDay { - events: [CalendarDayEvent], - date: Date, - header: string, -} - -export enum CalendarDateDisplayFormat { - Relative, - Normal -} +import { AppModels, CalendarDay, CalendarDateDisplayFormat } from "../shared/Models.slint"; export component Calendar inherits Rectangle { in property<[CalendarDay]> days; @@ -65,7 +47,7 @@ export component Calendar inherits Rectangle { } Rectangle { - Rectangle { + Rectangle { // Last bar delimiting days x: parent.width - 1px; y: header-height - 32px; width: 1px; @@ -76,7 +58,7 @@ export component Calendar inherits Rectangle { //background: green; HorizontalLayout { for day[day-index] in root.days: Rectangle { - Rectangle { + Rectangle { // Bar delimiting days x: 0; y: header-height - 32px; width: 1px; @@ -103,11 +85,18 @@ export component Calendar inherits Rectangle { if day.date == root.current-date : Rectangle { background: Palette.red; x: 0px; - width: parent.width; y: day-start-y + hour-spacing * root.current-time.hour + (root.current-time.minute / 60 * hour-spacing); + width: parent.width; height: 1px; + z: 100; } for event[event-index] in day.events : Rectangle { + Rectangle { + width: 100%; + height: 100%; + background: AppModels.get-source-color-from-id-as-color(event.sourceId); + opacity: 0.05; + } background: Palette.card-background; border-radius: 4px; x: 8px; @@ -118,7 +107,7 @@ export component Calendar inherits Rectangle { HorizontalLayout { Rectangle { width: 4px; - background: Palette.accent; + background: AppModels.get-source-color-from-id-as-color(event.sourceId); } VerticalLayout { padding: 16px; diff --git a/src/components/TaskLine.slint b/src/components/TaskLine.slint index 89d7173..5369bf5 100644 --- a/src/components/TaskLine.slint +++ b/src/components/TaskLine.slint @@ -2,6 +2,7 @@ import { ToggleButton } from "@selenite"; import { VPopupIconMenu, VTag, VText, VButton, VActionButton, VCheckBox, Svg, Palette } from "@selenite"; import { TaskEdit } from "./TaskEdit.slint"; import { Date } from "std-widgets.slint"; +import { AppModels } from "../shared/Models.slint"; export struct TaskLineEditData { title: string, @@ -13,6 +14,7 @@ export struct TaskLineEditData { export component TaskLine inherits VerticalLayout { in property title; in property source-name; + in property source-color; in property hide-source-name; in property scheduled; in property date; @@ -91,7 +93,7 @@ export component TaskLine inherits VerticalLayout { } } if !hide-source-name : source-name := VTag { - text-color: Palette.accent; + text-color: root.source-color; text: "\{root.source-name}"; } } diff --git a/src/modals/EditSourceModal.slint b/src/modals/EditSourceModal.slint index 23dbf98..0b15c55 100644 --- a/src/modals/EditSourceModal.slint +++ b/src/modals/EditSourceModal.slint @@ -8,11 +8,13 @@ import { Modal } from "../../external/selenite/components/Modal.slint"; export component EditSourceModal inherits Modal { private property source-id-to-edit: -1; private property name: ""; + private property color_: ""; // Well, cannot override 'color' private property path: ""; public function edit(source-id: int) { source-id-to-edit = source-id; root.name = AppModels.get-source-name-from-id(source-id); + root.color_ = AppModels.get-source-color-from-id-as-hex(source-id); root.path = AppModels.get-source-path-from-id(source-id); root.show(); } @@ -24,6 +26,10 @@ export component EditSourceModal inherits Modal { label: "Name"; text <=> root.name; } + colorInput := VTextInput { + label: "Color"; + text <=> root.color_; + } pathInput := VTextInput { label: "Path"; text <=> root.path; @@ -31,7 +37,7 @@ export component EditSourceModal inherits Modal { VButton { text: "Save"; clicked => { - AppActions.edit-source(source-id-to-edit, name, path); + AppActions.edit-source(source-id-to-edit, name, color_, path); root.close(); } } diff --git a/src/shared/Actions.slint b/src/shared/Actions.slint index 8ce2c28..721168e 100644 --- a/src/shared/Actions.slint +++ b/src/shared/Actions.slint @@ -1,5 +1,5 @@ import { Date, Time } from "std-widgets.slint"; -import { CalendarDay } from "../components/Calendar.slint"; +import { CalendarDay } from "./Models.slint"; export struct NewTaskData { sourceId: int, @@ -33,7 +33,7 @@ export global AppActions { callback task-clicked(int, int); callback source-clicked(int); callback add-source(name: string, path: string); - callback edit-source(sourceId: int, name: string, path: string); + callback edit-source(sourceId: int, name: string, color: string, path: string); callback toggle-show-completed-tasks(); callback delete-task-clicked(int, int); diff --git a/src/shared/Models.slint b/src/shared/Models.slint index 2c5e7ff..e044f22 100644 --- a/src/shared/Models.slint +++ b/src/shared/Models.slint @@ -1,5 +1,4 @@ import { Date, Time } from "std-widgets.slint"; -import { CalendarDay } from "../components/Calendar.slint"; export struct Source { id: int, @@ -37,6 +36,25 @@ export struct Day { relativeDaysDiff: int } +export struct CalendarDayEvent { + sourceId: int, + id: int, + title: string, + startsAt: Time, + endsAt: Time +} + +export struct CalendarDay { + events: [CalendarDayEvent], + date: Date, + header: string, +} + +export enum CalendarDateDisplayFormat { + Relative, + Normal +} + export global AppModels { in-out property<[Source]> sources-selected; in-out property default-source-index; @@ -48,5 +66,7 @@ export global AppModels { callback get-source-id-from-name(string) -> int; pure callback get-source-name-from-id(int) -> string; + pure callback get-source-color-from-id-as-color(int) -> color; + pure callback get-source-color-from-id-as-hex(int) -> string; pure callback get-source-path-from-id(int) -> string; } diff --git a/src/windows/AppWindow/AppWindow.cpp b/src/windows/AppWindow/AppWindow.cpp index 35d2b37..19ecdfb 100644 --- a/src/windows/AppWindow/AppWindow.cpp +++ b/src/windows/AppWindow/AppWindow.cpp @@ -12,6 +12,7 @@ #include "mirai-core/MarkdownDataProvider.h" #include "mirai-core/Mirai.h" #include "selenite/palette.h" +#include "slint_color.h" #include "slint_string.h" #include "ui.h" #include @@ -97,6 +98,19 @@ void AppWindow::setupCallbacks() return slint::SharedString(source->name()); }); + models().on_get_source_color_from_id_as_hex([&](int sourceId) { + auto source = miraiInstance_->getSourceById(sourceId); + assert(source); + return slint::SharedString(source->color()); + }); + + models().on_get_source_color_from_id_as_color([&](int sourceId) { + auto source = miraiInstance_->getSourceById(sourceId); + assert(source); + auto color = selenite::hexStringToColor(source->color()); + return slint::Color::from_rgb_uint8(color.r, color.g, color.b); + }); + models().on_get_source_path_from_id([&](int sourceId) { auto source = miraiInstance_->getSourceById(sourceId); assert(source); @@ -150,8 +164,11 @@ void AppWindow::setupCallbacks() miraiInstance_->addSource(std::string(name), "FileSystemMarkdown", std::move(file)); }); - actions().on_edit_source([&](int sourceId, slint::SharedString name, slint::SharedString path) { - miraiInstance_->editSource(sourceId, std::string(name), std::string(path)); + actions().on_edit_source([&](int sourceId, slint::SharedString name, slint::SharedString color, + slint::SharedString path) { + miraiInstance_->editSource( + sourceId, std::string(name), std::string(color), std::string(path) + ); }); actions().on_delete_task_clicked([&](int sourceId, int taskId) { diff --git a/src/windows/AppWindow/views/TasksView.slint b/src/windows/AppWindow/views/TasksView.slint index b25e88c..0879f2e 100644 --- a/src/windows/AppWindow/views/TasksView.slint +++ b/src/windows/AppWindow/views/TasksView.slint @@ -93,6 +93,7 @@ export component MainView inherits Rectangle { TaskLine { title: task.title; source-name: AppModels.get-source-name-from-id(task.sourceId); + source-color: AppModels.get-source-color-from-id-as-color(task.sourceId); scheduled: task.date.year != 0; date: day.date; checked: task.checked; @@ -136,6 +137,7 @@ export component MainView inherits Rectangle { TaskLine { title: task.title; source-name: AppModels.get-source-name-from-id(task.sourceId); + source-color: AppModels.get-source-color-from-id-as-color(task.sourceId); checked: task.checked; allow-edit-date: true; delete => {