From a15c23bb214fd9f4cae76679dce912d4a72bef0f Mon Sep 17 00:00:00 2001 From: Vyn Date: Fri, 1 Nov 2024 13:43:45 +0100 Subject: [PATCH] Add Source creation/edition + Add missing edit forms for tasks and events --- external/mirai-core/CMakeLists.txt | 2 - .../mirai-core/include/mirai-core/Config.h | 29 ----- .../mirai-core/include/mirai-core/Mirai.h | 11 +- .../mirai-core/include/mirai-core/Source.h | 8 +- external/mirai-core/src/Config.cpp | 30 ----- external/mirai-core/src/ConfigImpl.cpp | 48 -------- external/mirai-core/src/ConfigImpl.h | 27 ----- external/mirai-core/src/Mirai.cpp | 105 ++++++++++++++++-- external/mirai-core/src/Source.cpp | 10 +- external/mirai-core/src/View.cpp | 13 ++- external/selenite | 2 +- src/AppWindowBackend.cpp | 41 ++++++- src/AppWindowBackend.h | 2 + src/main.cpp | 15 +-- ui/AppWindow.slint | 4 +- ui/Backend.slint | 23 +++- ui/Utils.slint | 5 +- ui/components/Calendar.slint | 2 +- ui/components/EventGroup.slint | 44 ++++++-- ui/components/SideBar.slint | 35 ++++-- ui/components/TaskEdit.slint | 17 +-- ui/components/TaskLine.slint | 6 +- ui/windows/AddSourceWindow.slint | 37 ++++++ ui/windows/EditSourceWindow.slint | 47 ++++++++ 24 files changed, 358 insertions(+), 205 deletions(-) delete mode 100644 external/mirai-core/include/mirai-core/Config.h delete mode 100644 external/mirai-core/src/Config.cpp delete mode 100644 external/mirai-core/src/ConfigImpl.cpp delete mode 100644 external/mirai-core/src/ConfigImpl.h create mode 100644 ui/windows/AddSourceWindow.slint create mode 100644 ui/windows/EditSourceWindow.slint diff --git a/external/mirai-core/CMakeLists.txt b/external/mirai-core/CMakeLists.txt index 19c2ecf..50ce1b7 100644 --- a/external/mirai-core/CMakeLists.txt +++ b/external/mirai-core/CMakeLists.txt @@ -7,8 +7,6 @@ set(CMAKE_COMPILE_WARNING_AS_ERROR ON) add_library(mirai-core src/Mirai.cpp - src/Config.cpp - src/ConfigImpl.cpp src/Task.cpp src/Day.cpp src/Event.cpp diff --git a/external/mirai-core/include/mirai-core/Config.h b/external/mirai-core/include/mirai-core/Config.h deleted file mode 100644 index a2c5282..0000000 --- a/external/mirai-core/include/mirai-core/Config.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Mirai. Copyright (C) 2024 Vyn - * This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only) - * The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt - */ - -#pragma once - -#include -#include -#include - -namespace mirai -{ - -class ConfigImpl; - -class Config -{ - public: - Config(const std::string &path); - ~Config(); - - std::vector sources() const; - - private: - std::unique_ptr impl_; -}; -} // namespace mirai diff --git a/external/mirai-core/include/mirai-core/Mirai.h b/external/mirai-core/include/mirai-core/Mirai.h index 480d109..8edd526 100644 --- a/external/mirai-core/include/mirai-core/Mirai.h +++ b/external/mirai-core/include/mirai-core/Mirai.h @@ -19,7 +19,12 @@ class Mirai { public: - void loadSource(std::unique_ptr &&resource); + Mirai(const std::string &configFilePath); + 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 deleteSource(int id); void unloadAllSources(); void save(); std::optional> getSourceByName(const std::string &name); @@ -31,7 +36,9 @@ class Mirai Source *getSourceById(int id); private: + void loadConfig(const std::string &path); + void saveConfig(); std::vector> sources_; - // std::vector tags_; + std::string configPath_; }; } // namespace mirai diff --git a/external/mirai-core/include/mirai-core/Source.h b/external/mirai-core/include/mirai-core/Source.h index a45ba95..a6e8bf8 100644 --- a/external/mirai-core/include/mirai-core/Source.h +++ b/external/mirai-core/include/mirai-core/Source.h @@ -31,13 +31,15 @@ struct createEventParams { }; struct SourceConstructor { + std::string name; DataProvider *sourceDataProvider; }; class Source { public: - Source(SourceConstructor params) : data(params.sourceDataProvider) + Source(SourceConstructor params) + : data(params.sourceDataProvider), name_(params.name), type_("FileSystemMarkdown") { } @@ -56,6 +58,8 @@ class Source std::string type() const; DataProvider *dataProvider(); + void setName(const std::string &name); + void createTask(const createTaskParams &task); void removeTask(const Task &task); std::optional getTaskById(int taskId); @@ -86,6 +90,8 @@ class Source return nextId++; } + std::string name_; + std::string type_; DataProvider *data; }; } // namespace mirai diff --git a/external/mirai-core/src/Config.cpp b/external/mirai-core/src/Config.cpp deleted file mode 100644 index 17acfbe..0000000 --- a/external/mirai-core/src/Config.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Mirai. Copyright (C) 2024 Vyn - * This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only) - * The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt - */ - -#include "Config.h" -#include "ConfigImpl.h" -#include "nlohmann/json.hpp" -#include -#include -#include -#include -#include - -namespace mirai -{ - -Config::~Config() = default; - -Config::Config(const std::string &path) : impl_(new ConfigImpl(path)) -{ -} - -std::vector Config::sources() const -{ - return impl_->sources(); -} - -}; // namespace mirai diff --git a/external/mirai-core/src/ConfigImpl.cpp b/external/mirai-core/src/ConfigImpl.cpp deleted file mode 100644 index c2c2cd1..0000000 --- a/external/mirai-core/src/ConfigImpl.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Mirai. Copyright (C) 2024 Vyn - * This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only) - * The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt - */ - -#include "ConfigImpl.h" -#include "nlohmann/json.hpp" -#include -#include -#include -#include - -namespace mirai -{ -ConfigImpl::ConfigImpl(const std::string &path) : path_(path) -{ - std::ifstream file(path_); - if (!file) { - configJson_ = nlohmann::json::parse(R"( - { - "files": [] - } - )"); - return; - } - configJson_ = nlohmann::json::parse(file); -} - -std::vector ConfigImpl::sources() const -{ - std::vector sources; - assert(configJson_.is_object()); - assert(configJson_["files"].is_array()); - auto jsonSources = configJson_["files"]; - for (const auto &filePath : jsonSources) { - assert(filePath.is_string()); - sources.push_back(filePath.get()); - } - return sources; -} - -std::string ConfigImpl::path() const -{ - return path_; -} - -}; // namespace mirai diff --git a/external/mirai-core/src/ConfigImpl.h b/external/mirai-core/src/ConfigImpl.h deleted file mode 100644 index 6e877ac..0000000 --- a/external/mirai-core/src/ConfigImpl.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Mirai. Copyright (C) 2024 Vyn - * This file is licensed under version 3 of the GNU General Public License (GPL-3.0-only) - * The license can be found in the LICENSE file or at https://www.gnu.org/licenses/gpl-3.0.txt - */ - -#pragma once - -#include "nlohmann/json.hpp" -#include - -namespace mirai -{ - -class ConfigImpl -{ - public: - ConfigImpl(const std::string &path); - - std::vector sources() const; - std::string path() const; - - private: - std::string path_; - nlohmann::json configJson_; -}; -} // namespace mirai diff --git a/external/mirai-core/src/Mirai.cpp b/external/mirai-core/src/Mirai.cpp index 3a87c2b..4552b2c 100644 --- a/external/mirai-core/src/Mirai.cpp +++ b/external/mirai-core/src/Mirai.cpp @@ -5,30 +5,115 @@ */ #include "Mirai.h" -#include "Config.h" #include "DataProvider.h" +#include "MarkdownDataProvider.h" #include "Source.h" -#include "cpp-utils/debug.h" -#include "utils.h" +#include "nlohmann/json.hpp" #include #include #include -#include -#include +#include #include namespace mirai { -void Mirai::loadSource(std::unique_ptr &&resource) +void Mirai::loadConfig(const std::string &path) { - DataProvider *sourceDataProvider = resource.release(); + auto configJson = nlohmann::json::parse(R"( + { + "files": [] + } + )"); + std::ifstream file(path); + if (!file) { + + return; + } + configJson = nlohmann::json::parse(file); + + assert(configJson.is_object()); + assert(configJson["files"].is_array()); + auto jsonSources = configJson["files"]; + for (const auto &filePath : jsonSources) { + assert(filePath.is_object()); + const auto name = filePath["name"].get(); + const auto path = filePath["path"].get(); + 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} + )); + } +} + +void Mirai::saveConfig() +{ + std::ofstream file(configPath_); + if (!file.is_open()) { + std::cerr << "Can't save config to " << configPath_ << std::endl; + return; + } + auto configJson = nlohmann::json::parse(R"( + { + "files": [] + } + )"); + for (auto &source : sources_) { + nlohmann::json jsonSource; + jsonSource["name"] = source->name(); + auto dataProvider = dynamic_cast(source->dataProvider()); + jsonSource["path"] = dataProvider->path(); + jsonSource["type"] = "FileSystemMarkdown"; + configJson["files"].push_back(jsonSource); + } + file << configJson.dump(4); + file.close(); +} + +Mirai::Mirai(const std::string &configFilePath) : configPath_(configFilePath) +{ + loadConfig(configFilePath); +} + +void Mirai::addSource( + const std::string &name, const std::string &type, std::unique_ptr &&source +) +{ + DataProvider *sourceDataProvider = source.release(); sourceDataProvider->load(); - sources_.push_back( - std::make_unique(SourceConstructor{.sourceDataProvider = sourceDataProvider}) - ); + sources_.push_back(std::make_unique( + SourceConstructor{.name = name, .sourceDataProvider = sourceDataProvider} + )); + saveConfig(); }; +void Mirai::editSource(int id, const std::string &name, const std::string &path) +{ + auto source = getSourceById(id); + source->setName(name); + + DataProvider *sourceDataProvider = source->dataProvider(); + saveConfig(); +} + +void Mirai::deleteSource(int id) +{ + auto source = getSourceById(id); + sources_.erase( + std::remove_if( + sources_.begin(), sources_.end(), + [&](const std::unique_ptr &source) { + return source->id == id; + } + ), + sources_.end() + ); + + saveConfig(); +} + void Mirai::unloadAllSources() { sources_.clear(); diff --git a/external/mirai-core/src/Source.cpp b/external/mirai-core/src/Source.cpp index 67050a0..bf3dac2 100644 --- a/external/mirai-core/src/Source.cpp +++ b/external/mirai-core/src/Source.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace mirai @@ -144,13 +145,18 @@ std::vector Source::getUnscheduledTasks() std::string Source::name() const { - return data->name(); + return name_; +} + +void Source::setName(const std::string &name) +{ + name_ = name; } std::string Source::type() const { // There is only 1 type for now - return "MarkdownFile"; + return type_; } DataProvider *Source::dataProvider() diff --git a/external/mirai-core/src/View.cpp b/external/mirai-core/src/View.cpp index cfe4aff..765305a 100644 --- a/external/mirai-core/src/View.cpp +++ b/external/mirai-core/src/View.cpp @@ -84,12 +84,13 @@ void View::update() } // day's events - auto sourceEvents = day.events() | std::ranges::views::filter([&](const Event &event) { - return (day.date() >= todayDate) || - findFirst(event.queryTasks(), [&](const Task &task) { - return task.checked() == false; - }).has_value(); - }); + auto sourceEvents = + day.events() | std::ranges::views::filter([&](const Event &event) { + return (!shouldHideCompletedTasks() || day.date() >= todayDate) || + findFirst(event.queryTasks(), [&](const Task &task) { + return task.checked() == false; + }).has_value(); + }); if (day.date() >= todayDate || std::ranges::distance(sourceEvents) > 0) { if (!dates.contains(day.date())) { diff --git a/external/selenite b/external/selenite index 33d6a9d..a2e151c 160000 --- a/external/selenite +++ b/external/selenite @@ -1 +1 @@ -Subproject commit 33d6a9dee8437979b5a9bf5a716a4053f3ebf2fa +Subproject commit a2e151c99dd7811f348729aa08c098520cada519 diff --git a/src/AppWindowBackend.cpp b/src/AppWindowBackend.cpp index 47a370e..cde3e83 100644 --- a/src/AppWindowBackend.cpp +++ b/src/AppWindowBackend.cpp @@ -53,6 +53,7 @@ AppWindowBackend::AppWindowBackend(mirai::Mirai *miraiInstance) std::cerr << "Warning, no " << palettePath << " found" << std::endl; setSelenitePalette(mainWindow_->global(), palette.value()); setSelenitePalette(settingsWindow_->global(), palette.value()); + setSelenitePalette(addSourceWindow_->global(), palette.value()); } mainWindow_->global().set_sources(sourcesNames); @@ -116,6 +117,40 @@ void AppWindowBackend::setupCallbacks() mainWindow_->global().on_settings_clicked([&]() { settingsWindow_->show(); }); + mainWindow_->global().on_add_source_clicked([&]() { + addSourceWindow_->show(); + }); + mainWindow_->global().on_edit_source_clicked([&](int sourceId) { + auto source = miraiInstance_->getSourceById(sourceId); + assert(source); + auto markdownSource = dynamic_cast(source->dataProvider()); + editSourceWindow_->set_id(source->id); + editSourceWindow_->set_name(slint::SharedString(source->name())); + editSourceWindow_->set_path(slint::SharedString(markdownSource->path())); + editSourceWindow_->show(); + }); + addSourceWindow_->global().on_add_source([&](ui::AddSourceParam params) { + std::unique_ptr file = + std::make_unique(std::string(params.path)); + miraiInstance_->addSource( + std::string(params.name), std::string(params.type), std::move(file) + ); + addSourceWindow_->hide(); + reloadSources(); + reloadTasks(); + }); + editSourceWindow_->global().on_modify_source([&](ui::ModifySourceParam params) { + miraiInstance_->editSource(params.id, std::string(params.name), std::string(params.path)); + editSourceWindow_->hide(); + reloadSources(); + reloadTasks(); + }); + editSourceWindow_->global().on_delete_source([&](int sourceId) { + miraiInstance_->deleteSource(sourceId); + editSourceWindow_->hide(); + reloadSources(); + reloadTasks(); + }); mainWindow_->global().on_task_clicked([&](int sourceId, int taskId) { auto source = miraiInstance_->getSourceById(sourceId); assert(source); @@ -296,6 +331,7 @@ void AppWindowBackend::reloadTasks() auto &task = tasksForDate.at(taskIndex); slintDayTasks->push_back({ .sourceId = task.sourceId(), + .eventId = -1, .id = task.id(), .title = slint::SharedString(task.title()), .checked = task.checked(), @@ -320,6 +356,7 @@ void AppWindowBackend::reloadTasks() auto &task = eventTasks.at(taskIndex); slintTasks->push_back({ .sourceId = task.sourceId(), + .eventId = currentEvent.id(), .id = task.id(), .title = slint::SharedString(task.title()), .checked = task.checked(), @@ -336,6 +373,7 @@ void AppWindowBackend::reloadTasks() auto &task = unscheduledTasksView.at(taskIndex); unscheduledTasks_->push_back({ .sourceId = task.sourceId(), + .eventId = -1, .id = task.id(), .title = slint::SharedString(task.title()), .checked = task.checked(), @@ -389,7 +427,8 @@ void AppWindowBackend::reloadSources() mirai::MarkdownDataProvider *sourceProvider = dynamic_cast(source->dataProvider()); sources_->push_back( - {.name = slint::SharedString(source->name()), + {.id = source->id, + .name = slint::SharedString(source->name()), .selected = isSourceSelected && !noSourceSelected, .path = slint::SharedString(sourceProvider->path())} ); diff --git a/src/AppWindowBackend.h b/src/AppWindowBackend.h index 5c6379e..ddcdeb8 100644 --- a/src/AppWindowBackend.h +++ b/src/AppWindowBackend.h @@ -34,6 +34,8 @@ class AppWindowBackend slint::ComponentHandle mainWindow_ = ui::AppWindow::create(); slint::ComponentHandle settingsWindow_ = ui::SettingsWindow::create(); + slint::ComponentHandle addSourceWindow_ = ui::AddSourceWindow::create(); + slint::ComponentHandle editSourceWindow_ = ui::EditSourceWindow::create(); mirai::Mirai *miraiInstance_; mirai::View view_; diff --git a/src/main.cpp b/src/main.cpp index 909b6a6..9146d72 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,28 +6,15 @@ #include "AppWindowBackend.h" #include "evalyte-cpp-common/config.h" -#include "mirai-core/Config.h" -#include "mirai-core/DataProvider.h" -#include "mirai-core/MarkdownDataProvider.h" #include "mirai-core/Mirai.h" #include -#include #include int main(int argc, char **argv) { - mirai::Mirai mirai; - const auto configFilePath = evalyte::createConfigDirectoryPath("mirai") + "/config.json"; - mirai::Config config(configFilePath); - for (const auto &sourceFilePath : config.sources()) { - std::unique_ptr file = - std::make_unique(sourceFilePath); - mirai.loadSource(std::move(file)); - } - + mirai::Mirai mirai{configFilePath}; AppWindowBackend appWindow{&mirai}; appWindow.run(); - return 0; } diff --git a/ui/AppWindow.slint b/ui/AppWindow.slint index ad33ee8..7833eef 100644 --- a/ui/AppWindow.slint +++ b/ui/AppWindow.slint @@ -3,6 +3,8 @@ import { Button, VerticalBox, CheckBox } from "std-widgets.slint"; import { SideBar } from "./components/SideBar.slint"; import { MainView } from "MainView.slint"; import { SettingsWindow } from "SettingsWindow.slint"; +import { AddSourceWindow } from "windows/AddSourceWindow.slint"; +import { EditSourceWindow } from "windows/EditSourceWindow.slint"; import { Palette } from "@selenite"; export component AppWindow inherits Window { @@ -21,4 +23,4 @@ export component AppWindow inherits Window { } -export { Backend, Palette, SettingsWindow } // Export to make it visible to the C++ backend +export { Backend, Palette, SettingsWindow, AddSourceWindow, EditSourceWindow } // Export to make it visible to the C++ backend diff --git a/ui/Backend.slint b/ui/Backend.slint index 4cea021..c3b9923 100644 --- a/ui/Backend.slint +++ b/ui/Backend.slint @@ -34,7 +34,20 @@ export struct SaveEventParams { endsAt: Time } +export struct AddSourceParam { + name: string, + type: string, + path: string +} + +export struct ModifySourceParam { + id: int, + name: string, + path: string +} + export struct Source { + id: int, name: string, selected: bool, path: string @@ -42,10 +55,11 @@ export struct Source { export struct TaskData { sourceId: int, + eventId: int, id: int, title: string, + date: Date, checked: bool, - tags: [string], } export struct Event { @@ -87,6 +101,8 @@ export global Backend { callback source-clicked(int); callback tag-clicked(int); callback settings-clicked(); + callback add-source-clicked(); + callback edit-source-clicked(int); callback open-new-task-form(OpenNewTaskFormParams); callback open-edit-task-form(int, int); @@ -101,6 +117,11 @@ export global Backend { callback create-event(NewEventParams); callback save-event(SaveEventParams); + callback add-source(AddSourceParam); + callback modify-source(ModifySourceParam); + callback delete-source(int); + + // Utils pure callback format-date(Date) -> string; pure callback format-date-relative(Date) -> string; pure callback capitalize-string(string) -> string; diff --git a/ui/Utils.slint b/ui/Utils.slint index 4800524..5b9c1ab 100644 --- a/ui/Utils.slint +++ b/ui/Utils.slint @@ -9,6 +9,9 @@ export global Utils { } public pure function time-to-string(time: Time) -> string { - return "\{format-zero-padding(time.hour)}h\{format-zero-padding(time.minute)}"; + if (time.minute == 0) { + return "\{time.hour}"; + } + return "\{time.hour}:\{format-zero-padding(time.minute)}"; } } diff --git a/ui/components/Calendar.slint b/ui/components/Calendar.slint index f5b523f..0d2e12f 100644 --- a/ui/components/Calendar.slint +++ b/ui/components/Calendar.slint @@ -50,7 +50,7 @@ export component Calendar inherits Rectangle { VText { vertical-alignment: center; horizontal-alignment: right; - text: "\{index}h"; + text: "\{index}"; } } diff --git a/ui/components/EventGroup.slint b/ui/components/EventGroup.slint index f868781..64cc4fb 100644 --- a/ui/components/EventGroup.slint +++ b/ui/components/EventGroup.slint @@ -1,11 +1,13 @@ import { Backend, TaskData, Event } from "../Backend.slint"; import { ScrollView } from "std-widgets.slint"; -import { VCheckBox, VButton, VActionButton, Svg, VTag, VPopupIconMenu, VText, Palette } from "@selenite"; +import { VCheckBox, VTextInput, VButton, VActionButton, Svg, VTag, VPopupIconMenu, VText, Palette } from "@selenite"; import { TaskLine } from "./TaskLine.slint"; import { Utils } from "../Utils.slint"; export component EventGroup { in property event; + private property show-add-task: false; + private property edit-name: false; eventPopup := VPopupIconMenu { VActionButton { @@ -13,17 +15,16 @@ export component EventGroup { icon-colorize: Colors.greenyellow; icon-size: 1.5rem; border-radius: 0; - clicked => { Backend.open-new-task-form({ - eventSourceId: event.sourceId, - eventId: event.id, - })} + clicked => { + root.show-add-task = true; + } } VActionButton { icon-svg: Svg.pen; icon-colorize: Colors.grey; icon-size: 1.5rem; border-radius: 0; - clicked => { Backend.open-edit-event-form(event.sourceId, event.id) } + clicked => { edit-name = true; } } VActionButton { @@ -48,15 +49,14 @@ export component EventGroup { spacing: 4px; VText { text: Utils.time-to-string(event.startsAt); + horizontal-alignment: center; color: Palette.accent; } HorizontalLayout { alignment: center; Rectangle { - width: 4px; + width: 2px; background: Palette.accent; - border-radius: 8px; - } } VText { @@ -72,10 +72,24 @@ export component EventGroup { padding-top: 32px; padding-bottom: 32px; padding-right: 0px; - VText { + if !edit-name : VText { text: event.title; font-size: 1.1rem; } + if edit-name : title := VTextInput { + text: event.title; + accepted => { + Backend.save-event({ + sourceId: event.sourceId, + id: event.id, + title: title.text, + //date: event.date, + startsAt: event.startsAt, + endsAt: event.endsAt, + }); + root.edit-name = false; + } + } for task[taskIndex] in event.tasks: VerticalLayout { padding-top: taskIndex == 0 ? 16px : 0px; padding-bottom: 8px; @@ -85,6 +99,16 @@ export component EventGroup { task-index: task.id; } } + if show-add-task : taskInput := VTextInput { + accepted => { + Backend.create-task({ + sourceId: event.sourceId, + eventId: event.id, + title: taskInput.text, + }); + root.show-add-task = false; + } + } } } diff --git a/ui/components/SideBar.slint b/ui/components/SideBar.slint index 26d3841..cd71a9b 100644 --- a/ui/components/SideBar.slint +++ b/ui/components/SideBar.slint @@ -1,5 +1,5 @@ import { Backend } from "../Backend.slint"; -import { VButton, ToggleButton, VText, Svg, Palette } from "@selenite"; +import { VButton, ToggleButton, VActionButton, VText, Svg, Palette } from "@selenite"; export component SideBar inherits Rectangle { background: Palette.pane; @@ -8,9 +8,20 @@ export component SideBar inherits Rectangle { height: parent.height; padding: 16px; spacing: 16px; - VText { - text: "Sources"; - font-size: 1.5rem; + HorizontalLayout { + alignment: space-between; + spacing: 64px; + VText { + text: "Sources"; + font-size: 1.5rem; + } + + VActionButton { + icon-svg: Svg.plus; + icon-colorize: Palette.green; + background: transparent; + clicked => { Backend.add-source-clicked() } + } } VerticalLayout { alignment: space-between; @@ -23,23 +34,31 @@ export component SideBar inherits Rectangle { text-alignment: left; active: Backend.no-source-selected; clicked => { Backend.source-clicked(-1) } + + } for item[index] in Backend.sources-selected: ToggleButton { text: item.name; text-alignment: left; active: item.selected; clicked => { Backend.source-clicked(index) } + VActionButton { + visible: parent.active; + icon-svg: Svg.cog; + background: transparent; + clicked => { Backend.edit-source-clicked(item.id) } + } } } - /*VerticalLayout { + VerticalLayout { spacing: 4px; - VButton { + /*VButton { icon-svg: Svg.cog; text: "Settings"; background: transparent; clicked => { Backend.settings-clicked() } - } - }*/ + }*/ + } } } } diff --git a/ui/components/TaskEdit.slint b/ui/components/TaskEdit.slint index a77d529..1a2117d 100644 --- a/ui/components/TaskEdit.slint +++ b/ui/components/TaskEdit.slint @@ -1,13 +1,15 @@ import { Backend, TaskData } from "../Backend.slint"; -import { Button, VerticalBox, CheckBox, ScrollView, ComboBox } from "std-widgets.slint"; +import { Button, VerticalBox, CheckBox, Date, ScrollView, ComboBox } from "std-widgets.slint"; import { VPopupIconMenu, VDatePicker, VTimePicker, VCheckBox, VButton, VTag, VText, VTextInput, Svg, Palette } from "@selenite"; import { NewTaskData, SaveTaskData } from "../Backend.slint"; export component TaskEdit inherits VerticalLayout { - in-out property task; + in-out property task; out property should-show; - public function show(task: SaveTaskData) { + private property newDate: task.date; + + public function show(task: TaskData) { root.task = task; should-show = true; } @@ -16,8 +18,6 @@ export component TaskEdit inherits VerticalLayout { } callback accepted(SaveTaskData); - - if !should-show : Rectangle {} if should-show : Rectangle { @@ -26,8 +26,8 @@ export component TaskEdit inherits VerticalLayout { id: task.id, sourceId: task.sourceId, title: newTaskTitleInput.text, - scheduled: taskDateInput.date.year != 0, - date: taskDateInput.date + scheduled: newDate.year != 0, + date: newDate }); } background: Palette.background; @@ -43,9 +43,10 @@ export component TaskEdit inherits VerticalLayout { HorizontalLayout { alignment: start; spacing: 8px; - taskDateInput := VDatePicker { + if root.task.eventId == -1 : taskDateInput := VDatePicker { date: task.date; enabled: true; + edited(date) => { newDate = date; } } VButton { text: "Modify"; diff --git a/ui/components/TaskLine.slint b/ui/components/TaskLine.slint index 9bfecaf..0e6f7ad 100644 --- a/ui/components/TaskLine.slint +++ b/ui/components/TaskLine.slint @@ -44,8 +44,10 @@ export component TaskLine inherits VerticalLayout { taskEdit.show({ sourceId: task.sourceId, id: task.id, + eventId: task.eventId, title: task.title, scheduled: root.date.year != 0, + checked: task.checked, date: date, }); } @@ -87,10 +89,10 @@ export component TaskLine inherits VerticalLayout { Backend.task-clicked(source-index, task-index) } } - for tag[tag-index] in task.tags: VTag { + /*for tag[tag-index] in task.tags: VTag { text: tag; size: 0.8rem; - } + }*/ } } diff --git a/ui/windows/AddSourceWindow.slint b/ui/windows/AddSourceWindow.slint new file mode 100644 index 0000000..32e6907 --- /dev/null +++ b/ui/windows/AddSourceWindow.slint @@ -0,0 +1,37 @@ +import { Backend } from "../Backend.slint"; +import { VerticalBox, CheckBox } from "std-widgets.slint"; +import { SideBar } from "../components/SideBar.slint"; +import { VButton, VText, VTextInput, Palette } from "@selenite"; + +export component AddSourceWindow inherits Window { + + title: "Mirai - Add source"; + min-height: 100px; + max-height: 4000px; // needed, otherwise the window wants to fit the content (on Swaywm) + min-width: 400px; + default-font-size: 16px; + background: Palette.background; + + VerticalLayout { + padding: 16px; + spacing: 8px; + nameInput := VTextInput { + label: "Name"; + } + pathInput := VTextInput { + label: "Path"; + } + VButton { + text: "Create"; + clicked => { + Backend.add-source({ + name: nameInput.text, + type: "FileSystemMarkdown", + path: pathInput.text + }) + } + } + } +} + +export { Backend, Palette } // Export to make it visible to the C++ backend diff --git a/ui/windows/EditSourceWindow.slint b/ui/windows/EditSourceWindow.slint new file mode 100644 index 0000000..81dd00c --- /dev/null +++ b/ui/windows/EditSourceWindow.slint @@ -0,0 +1,47 @@ +import { Backend } from "../Backend.slint"; +import { VerticalBox, CheckBox } from "std-widgets.slint"; +import { SideBar } from "../components/SideBar.slint"; +import { VButton, VText, VTextInput, Palette } from "@selenite"; + +export component EditSourceWindow inherits Window { + in-out property id; + in-out property name <=> nameInput.text; + in-out property path <=> pathInput.text; + + title: "Mirai - Edit source"; + min-height: 100px; + max-height: 4000px; // needed, otherwise the window wants to fit the content (on Swaywm) + min-width: 400px; + default-font-size: 16px; + background: Palette.background; + + VerticalLayout { + padding: 16px; + spacing: 8px; + nameInput := VTextInput { + label: "Name"; + } + pathInput := VTextInput { + label: "Path"; + } + VButton { + text: "Save"; + clicked => { + Backend.modify-source({ + id: root.id, + name: nameInput.text, + path: pathInput.text + }) + } + } + VButton { + text: "Delete"; + background-color: Colors.red; + double-clicked => { + Backend.delete-source(root.id) + } + } + } +} + +export { Backend, Palette } // Export to make it visible to the C++ backend