diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ba2f8d..15aca42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ qt_add_qml_module(mirai src/qml/TaskItem.qml src/qml/forms/TaskForm.qml src/qml/forms/FilesForm.qml + src/qml/forms/TagsConfigForm.qml src/qml/components/TabSelector.qml src/qml/components/Tag.qml src/qml/components/Calendar.qml @@ -61,10 +62,12 @@ qt_add_qml_module(mirai SOURCES src/Backend.h src/Backend.cpp src/TaskItem.h src/TaskItem.cpp + src/Tag.h src/Tag.cpp src/TasksFile.h src/TasksFile.cpp RESOURCES src/images/calendar.png src/images/add.png + src/images/settings.png ) target_link_libraries(mirai PRIVATE Qt6::Quick) diff --git a/src/Backend.cpp b/src/Backend.cpp index 26bdde1..9a9625b 100644 --- a/src/Backend.cpp +++ b/src/Backend.cpp @@ -197,7 +197,10 @@ void Backend::rebuildQMLTasksList() QMLTags.clear(); for (auto &tag : mirai.getTags()) { - QMLTags.push_back(QString::fromStdString(tag)); + QMLTags.push_back({ + .name = QString::fromStdString(tag), + .color = getTagColor(QString::fromStdString(tag)), + }); } QMLActiveTagsFilter.clear(); @@ -248,3 +251,45 @@ QString Backend::getTagColor(QString tag) } return tagsConfig[tag]; } + +void Backend::saveTagsColor(QVariant modifiedTags) +{ + auto aa = modifiedTags.toList(); + for (auto bb : aa) { + auto cc = bb.toMap(); + std::cout << cc["name"].toString().toStdString() << ": " + << cc["color"].toString().toStdString() << std::endl; + tagsConfig[cc["name"].toString()] = cc["color"].toString(); + } + rebuildQMLTasksList(); + emit tagsChanged(); + emit tasksChanged(); + saveConfig(); +} + +void Backend::saveConfig() +{ + QJsonObject rootJson; + + QJsonArray filesJson; + for (auto &file : mirai.getFiles()) { + filesJson.append(QString::fromStdString(file->getPath())); + } + rootJson["files"] = filesJson; + + QJsonObject tagsJson; + for (auto &tag : tagsConfig.keys()) { + QJsonObject tagConfig; + tagConfig["color"] = getTagColor(tag); + tagsJson[tag] = tagConfig; + } + rootJson["tags"] = tagsJson; + + QFile configFile(QDir::homePath() + "/.config/mirai/config.json"); + if (!configFile.open(QIODevice::WriteOnly)) { + qWarning() << "Cannot save config"; + return; + } + configFile.write(QJsonDocument(rootJson).toJson()); + configFile.close(); +} diff --git a/src/Backend.h b/src/Backend.h index 02906bd..28a3596 100644 --- a/src/Backend.h +++ b/src/Backend.h @@ -10,6 +10,7 @@ #include "QtCore/qcontainerfwd.h" #include "QtCore/qtmetamacros.h" #include "QtCore/qvariant.h" +#include "Tag.h" #include "TasksFile.h" #include "core/Mirai.h" #include "core/TasksView.h" @@ -33,7 +34,7 @@ class Backend : public QObject QML_ELEMENT Q_PROPERTY(QVariant tasks READ getTasks NOTIFY tasksChanged) Q_PROPERTY(QVariant files READ getFiles NOTIFY filesChanged) - Q_PROPERTY(QVariant tags READ getTags NOTIFY tasksChanged) + Q_PROPERTY(QVariant tags READ getTags NOTIFY tagsChanged) Q_PROPERTY(QVariant activeTagsFilter READ getActiveTagsFilter NOTIFY tasksChanged) Q_PROPERTY(QVariant activeFilesFilter READ getActiveFilesFilter NOTIFY tasksChanged) Q_PROPERTY(bool shouldHideCompletedTasks READ shouldHideCompletedTasks WRITE hideCompletedTasks @@ -54,6 +55,7 @@ class Backend : public QObject Q_INVOKABLE void removeTodo(int todoIndex); Q_INVOKABLE void hideCompletedTasks(bool shouldHide); Q_INVOKABLE QString getTagColor(QString tag); + Q_INVOKABLE void saveTagsColor(QVariant tags); private: void rebuildQMLTasksList(); @@ -64,13 +66,14 @@ class Backend : public QObject QVariant getActiveTagsFilter(); QVariant getActiveFilesFilter(); bool shouldHideCompletedTasks(); + void saveConfig(); mirai::Mirai mirai; mirai::TasksView view; QList QMLTasks; QList QMLTasksFiles; - QList QMLTags; + QList QMLTags; QList QMLActiveTagsFilter; QList QMLActiveFilesFilter; QMap tagsConfig; @@ -80,6 +83,7 @@ class Backend : public QObject signals: void tasksChanged(); + void tagsChanged(); void filesChanged(); }; diff --git a/src/Tag.cpp b/src/Tag.cpp new file mode 100644 index 0000000..17ea211 --- /dev/null +++ b/src/Tag.cpp @@ -0,0 +1,17 @@ +/* + * 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 "Tag.h" + +QString QMLTag::getName() +{ + return name; +} + +QString QMLTag::getColor() +{ + return color; +} diff --git a/src/Tag.h b/src/Tag.h new file mode 100644 index 0000000..7945c2a --- /dev/null +++ b/src/Tag.h @@ -0,0 +1,29 @@ +/* + * 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 + */ + +#ifndef QML_TAG_H +#define QML_TAG_H + +#include +#include +#include + +struct QMLTag { + + Q_GADGET + Q_PROPERTY(QString name READ getName) + Q_PROPERTY(QString color READ getColor) + QML_VALUE_TYPE(tag) + + public: + QString getName(); + QString getColor(); + + QString name; + QString color; +}; + +#endif diff --git a/src/images/settings.png b/src/images/settings.png new file mode 100644 index 0000000..ead5906 Binary files /dev/null and b/src/images/settings.png differ diff --git a/src/qml/AppIcon.qml b/src/qml/AppIcon.qml index a40a18f..2ee0afe 100644 --- a/src/qml/AppIcon.qml +++ b/src/qml/AppIcon.qml @@ -11,5 +11,12 @@ import Mirai Button { icon.color: MiraiColorPalette.buttonIcon - background: Rectangle { color: "transparent" } + background: Rectangle { + color: "transparent" + HoverHandler { + id: mouse + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + cursorShape: Qt.PointingHandCursor + } + } } diff --git a/src/qml/SideMenu.qml b/src/qml/SideMenu.qml index 4981003..23a3066 100644 --- a/src/qml/SideMenu.qml +++ b/src/qml/SideMenu.qml @@ -7,6 +7,7 @@ import QtQuick import QtQuick.Window import QtQuick.Layouts +import QtQuick.Controls import Mirai ColumnLayout { @@ -50,9 +51,20 @@ ColumnLayout { Item { Layout.preferredHeight: 16 } - AppText { - text: "Tags" - font.pixelSize: 32 + RowLayout { + AppText { + text: "Tags" + font.pixelSize: 32 + } + Item { Layout.fillWidth: true } + AppIcon { + icon.source: "qrc:/qt/qml/Mirai/src/images/settings.png" + icon.color: colorPalette.selected.textPlaceholder + onClicked: { + tagsForm.reset(); + tagsFormPopup.open(); + } + } } Item { Layout.preferredHeight: 16 } @@ -62,25 +74,26 @@ ColumnLayout { Rectangle { Layout.preferredHeight: childrenRect.height Layout.fillWidth: true - color: backend.activeTagsFilter.includes(modelData) ? MiraiColorPalette.filterSelected : mouse.hovered ? MiraiColorPalette.filterHovered : "transparent" + color: backend.activeTagsFilter.includes(modelData.name) ? MiraiColorPalette.filterSelected : mouse.hovered ? MiraiColorPalette.filterHovered : "transparent" radius: 4 QtObject { id: internal - property string configTagColor: backend.getTagColor(modelData) } AppText { - - text: modelData - color: internal.configTagColor != "" ? internal.configTagColor : MiraiColorPalette.text + text: modelData.name + color: { + console.log("ttagg", modelData.name, modelData.color) + return modelData.color + } padding: 4 } MouseArea { anchors.fill: parent onClicked: { - if (backend.activeTagsFilter.includes(modelData)) { - backend.removeTagFilter(modelData) + if (backend.activeTagsFilter.includes(modelData.name)) { + backend.removeTagFilter(modelData.name) } else { - backend.addTagFilter(modelData) + backend.addTagFilter(modelData.name) } } HoverHandler { @@ -104,10 +117,27 @@ ColumnLayout { } } - /*AppButton { - text: `Settings` - onClicked: { - root.openSettings() + Popup { + parent: Overlay.overlay + id: tagsFormPopup + width: parent.width * 0.75 + implicitHeight: tagsForm.height + padding * 2 + x: Math.round((parent.width - width) / 2) + y: Math.round((parent.height * 0.4) / 2) + padding: 8 + background: Rectangle { + border.color: colorPalette.selected.modalBorder + border.width: 2 + color: colorPalette.selected.pane + radius: 4 } - }*/ + TagsConfigForm { + id: tagsForm + width: parent.width + onConfirmed: (tags) => { + tagsFormPopup.close() + backend.saveTagsColor(tags) + } + } + } } diff --git a/src/qml/components/Tag.qml b/src/qml/components/Tag.qml index 6e75877..85ed919 100644 --- a/src/qml/components/Tag.qml +++ b/src/qml/components/Tag.qml @@ -20,11 +20,10 @@ Rectangle { QtObject { id: internal - property string configTagColor: backend.getTagColor(control.text) } AppText { - color: internal.configTagColor != "" ? internal.configTagColor : control.textColor + color: backend.getTagColor(control.text) padding: 2 leftPadding: 6 rightPadding: 6 diff --git a/src/qml/forms/TagsConfigForm.qml b/src/qml/forms/TagsConfigForm.qml new file mode 100644 index 0000000..f4323dc --- /dev/null +++ b/src/qml/forms/TagsConfigForm.qml @@ -0,0 +1,77 @@ +/* + * 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 + */ + +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import Mirai + +ColumnLayout { + id: form + spacing: 6 + signal confirmed(tags: var) + + function reset() { + internal.tags = Qt.binding(function () { return [] }) + internal.tags = Qt.binding(function () { return backend.tags.map(tag => { + return {name: tag.name, color: tag.color} + })}) + } + + QtObject { + id: internal + property var tags: [] + } + + Repeater { + id: tagsList + model: internal.tags + RowLayout { + Rectangle { + id: newTagColor + color: colorDialog.selectedColor + Layout.fillHeight: true + Layout.preferredWidth: 32 + + MouseArea { + anchors.fill: parent + onClicked: { + colorDialog.open() + } + HoverHandler { + id: mouse + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + cursorShape: Qt.PointingHandCursor + } + } + } + + ColorDialog { + id: colorDialog + selectedColor: modelData.color + onAccepted: { + colorDialog.selectedColor = selectedColor + internal.tags[index].color = selectedColor + } + } + + AppText { + text: modelData.name + color: colorDialog.selectedColor + } + } + } + + AppButton { + text: "Save" + onClicked: { + form.confirmed(internal.tags) + } + } +} +