commit 8bbbff7fead203237afdbf7568d8fb42f297bdb5 Author: Aurélie Delhaie Date: Mon Dec 12 20:57:18 2022 +0100 First commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..c0b426f Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45aa0c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pro.* \ No newline at end of file diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..c56a7de --- /dev/null +++ b/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleExecutable + TaskBoard + CFBundleIconFile + + CFBundleIdentifier + com.aureliedelhaie.TaskBoard + CFBundlePackageType + APPL + CFBundleSignature + ???? + LSMinimumSystemVersion + 10.14 + NSPrincipalClass + NSApplication + NSSupportsAutomaticGraphicsSwitching + + CFBundleIconFile + icon.icns + + diff --git a/TaskBoard.pro b/TaskBoard.pro new file mode 100644 index 0000000..65e0306 --- /dev/null +++ b/TaskBoard.pro @@ -0,0 +1,108 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++17 + +win32:VERSION = 0.1.0.0 # major.minor.patch.build +else:VERSION = 0.1.0 # major.minor.patch + +DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\" +DEFINES += APP_NAME=\"\\\"TaskBoard\\\"\" + +win32 { + message("Build for Windows") + QMAKE_CXXFLAGS_RELEASE -= -O + QMAKE_CXXFLAGS_RELEASE -= -O1 + QMAKE_CXXFLAGS_RELEASE *= -O2 + DEFINES += APP_OS=\"\\\"Windows\\\"\" + DEFINES += APP_OS_VERSION=\"\\\"$$system(ver)\\\"\" + equals(QMAKE_TARGET.arch, arm64) { + message("CPU Architecture : aarch64") + DEFINES += APP_ARCH=\"\\\"arm64\\\"\" + } + equals(QMAKE_TARGET.arch, x86_64) { + message("CPU Architecture : x64") + QMAKE_CXXFLAGS_RELEASE += -favor:INTEL64 + DEFINES += APP_ARCH=\"\\\"x64\\\"\" + } + RC_ICONS = icon.ico + QMAKE_TARGET_COMPANY = "Aurelie Delhaie" + QMAKE_TARGET_PRODUCT = "TaskBoard" + QMAKE_TARGET_DESCRIPTION = "TaskBoard" +} + +macx { + message("Build for macOS") + ICON = icon.icns + QMAKE_INFO_PLIST = Info.plist + QMAKE_CXXFLAGS_RELEASE -= -O + QMAKE_CXXFLAGS_RELEASE -= -O1 + QMAKE_CXXFLAGS_RELEASE -= -O2 + QMAKE_CXXFLAGS_RELEASE *= -O3 + QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64 + DEFINES += APP_OS=\"\\\"macOS\\\"\" + DEFINES += APP_OS_VERSION=\"\\\"$$system(uname -r)\\\"\" + DEFINES += APP_ARCH=\"\\\"universal\\\"\" +} + +linux-* { + message("Build for Linux") + DEFINES += APP_OS=\"\\\"$$system(cat /etc/issue | cut -d\' \' -f1)\\\"\" + DEFINES += APP_OS_VERSION=\"\\\"$$system(uname -r)\\\"\" + DEFINES += APP_ARCH=\"\\\"$$system(uname -m)\\\"\" + ARCH = $$system(uname -m) + equals(ARCH, aarch64) { + message("CPU Architecture : aarch64") + QMAKE_CXXFLAGS_RELEASE += -mtune=cortex-a72 + } + equals(ARCH, amd64) { + message("CPU Architecture : amd64") + QMAKE_CXXFLAGS_RELEASE += -march=skylake + } + QMAKE_CXXFLAGS_RELEASE *= -O3 +} + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + src/frames/aboutdialog.cpp \ + src/models/board.cpp \ + src/main.cpp \ + src/frames/mainwindow.cpp \ + src/frames/namedialog.cpp \ + src/frames/prefdialog.cpp \ + src/models/priority.cpp \ + src/models/status.cpp \ + src/models/task.cpp \ + src/frames/taskdialog.cpp \ + src/tools.cpp + +HEADERS += \ + src/frames/aboutdialog.h \ + src/models/board.h \ + src/frames/mainwindow.h \ + src/frames/namedialog.h \ + src/frames/prefdialog.h \ + src/models/priority.h \ + src/models/status.h \ + src/models/task.h \ + src/frames/taskdialog.h \ + src/tools.h + +FORMS += \ + src/frames/aboutdialog.ui \ + src/frames/mainwindow.ui \ + src/frames/namedialog.ui \ + src/frames/prefdialog.ui \ + src/frames/taskdialog.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +RESOURCES += \ + resources.qrc diff --git a/icon.icns b/icon.icns new file mode 100644 index 0000000..b9957b2 Binary files /dev/null and b/icon.icns differ diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..900e111 Binary files /dev/null and b/icon.ico differ diff --git a/resources.qrc b/resources.qrc new file mode 100644 index 0000000..d479d41 --- /dev/null +++ b/resources.qrc @@ -0,0 +1,5 @@ + + + resources/logo.png + + diff --git a/resources/.DS_Store b/resources/.DS_Store new file mode 100644 index 0000000..c777943 Binary files /dev/null and b/resources/.DS_Store differ diff --git a/resources/logo.png b/resources/logo.png new file mode 100644 index 0000000..980039f Binary files /dev/null and b/resources/logo.png differ diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..efa3619 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/frames/aboutdialog.cpp b/src/frames/aboutdialog.cpp new file mode 100644 index 0000000..8e2e0b7 --- /dev/null +++ b/src/frames/aboutdialog.cpp @@ -0,0 +1,16 @@ +#include "aboutdialog.h" +#include "ui_aboutdialog.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + ui->setupUi(this); + ui->appName->setText(QString("%1 (%2)").arg(APP_NAME, APP_ARCH)); + ui->version->setText(QString("v%1").arg(APP_VERSION)); +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} diff --git a/src/frames/aboutdialog.h b/src/frames/aboutdialog.h new file mode 100644 index 0000000..4474ece --- /dev/null +++ b/src/frames/aboutdialog.h @@ -0,0 +1,22 @@ +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include + +namespace Ui { +class AboutDialog; +} + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = nullptr); + ~AboutDialog(); + +private: + Ui::AboutDialog *ui; +}; + +#endif // ABOUTDIALOG_H diff --git a/src/frames/aboutdialog.ui b/src/frames/aboutdialog.ui new file mode 100644 index 0000000..b493c31 --- /dev/null +++ b/src/frames/aboutdialog.ui @@ -0,0 +1,116 @@ + + + AboutDialog + + + Qt::ApplicationModal + + + + 0 + 0 + 419 + 323 + + + + + 419 + 323 + + + + + 419 + 323 + + + + About TaskBoard + + + true + + + + + + + + + 64 + 64 + + + + + 16777215 + 64 + + + + image: url(:/images/resources/logo.png); + + + + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + font-size: 20px; + + + TextLabel + + + Qt::AlignCenter + + + + + + + TextLabel + + + Qt::AlignCenter + + + + + + + Made with ♥ by Aurélie + + + Qt::AlignCenter + + + + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> +p, li { white-space: pre-wrap; } +hr { height: 1px; border-width: 0; } +</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:700;">TODO: </span>Third parties</p></body></html> + + + + + + + + + + diff --git a/src/frames/mainwindow.cpp b/src/frames/mainwindow.cpp new file mode 100644 index 0000000..12300c9 --- /dev/null +++ b/src/frames/mainwindow.cpp @@ -0,0 +1,283 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include + +#include "prefdialog.h" +#include "aboutdialog.h" +#include "namedialog.h" +#include "taskdialog.h" +#include "../tools.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + connect(ui->actionPreferences, &QAction::triggered, this, &MainWindow::openPreferences); + connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::openAbout); + connect(ui->actionNew, &QAction::triggered, this, &MainWindow::onNewBoardClick); + connect(ui->listWidget, &QListWidget::currentRowChanged, this, &MainWindow::onBoardSelected); + connect(ui->actionNew_task, &QAction::triggered, this, &MainWindow::onNewTaskClick); + connect(ui->treeWidget, &QTreeWidget::itemDoubleClicked, this, &MainWindow::onEditTask); + this->priorities = defaultPriorities(); + this->status = defaultStatus(); +} + +MainWindow::~MainWindow() +{ + for (int i = 0; i < boards.count(); i++) + { + Board *b = boards.takeAt(i); + delete b; + } + delete ui; +} + +void MainWindow::openPreferences() +{ + PrefDialog dialog(this); + if (dialog.exec() == QDialog::DialogCode::Accepted) + { + this->priorities = dialog.getPriorities(); + this->status = dialog.getStatus(); + } +} + +void MainWindow::openAbout() +{ + AboutDialog dialog(this); + dialog.exec(); +} + +void MainWindow::onNewBoardClick() +{ + NameDialog dialog("Create a board", "New empty board", this); + if (dialog.exec() == QDialog::DialogCode::Accepted) + { + QString name = dialog.getChoosenName(); + Board *b = new Board(name); + boards.append(b); + QListWidgetItem *item = new QListWidgetItem(name); + ui->listWidget->addItem(item); + } +} + +void MainWindow::onNewTaskClick() +{ + if (selectedBoardIndex > -1) + { + TaskDialog dialog(status, priorities, this); + if (dialog.exec() == QDialog::DialogCode::Accepted) + { + Task t = dialog.getTask(); + Board *b = boards[selectedBoardIndex]; + b->add(t); + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setText(0, t.getTitle()); + item->setText(1, getStatusLabel(t.getStatusUUID())); + item->setText(2, getPriorityLabel(t.getPriorityUUID())); + item->setText(3, t.getExpectedFor().toString()); + + QBrush bgColor = item->background(1); + QBrush fgColor = item->foreground(1); + bgColor.setColor(getStatusColor(t.getStatusUUID(), bgColor.color())); + bgColor.setStyle(Qt::BrushStyle::SolidPattern); + fgColor.setColor(Tools::getForegroundColor(bgColor.color())); + item->setBackground(1, bgColor); + item->setForeground(1, fgColor); + + bgColor = item->background(2); + fgColor = item->foreground(2); + bgColor.setColor(getPriorityColor(t.getPriorityUUID(), bgColor.color())); + bgColor.setStyle(Qt::BrushStyle::SolidPattern); + fgColor.setColor(Tools::getForegroundColor(bgColor.color())); + item->setBackground(2, bgColor); + item->setForeground(2, fgColor); + + ui->treeWidget->addTopLevelItem(item); + } + } +} + +void MainWindow::onBoardSelected(int i) +{ + selectedBoardIndex = i; + if (selectedBoardIndex > -1) + { + Board *b = boards[selectedBoardIndex]; + ui->label->setText(b->getName()); + ui->actionNew_task->setDisabled(false); + } + else + { + ui->label->setText("<- Select a board"); + ui->actionNew_task->setDisabled(true); + } + redrawTaskTree(); +} + +void MainWindow::onEditTask(QTreeWidgetItem *item) +{ + if (item != nullptr && selectedBoardIndex > -1) + { + Board *b = boards[selectedBoardIndex]; + int row = ui->treeWidget->indexOfTopLevelItem(item); + Task *t = b->taskAt(row); + if (t != nullptr) + { + TaskDialog dialog(t, status, priorities, this); + if (dialog.exec() == QDialog::DialogCode::Accepted) + { + Task editedTask = dialog.getTask(); + t->update(editedTask); + item->setText(0, editedTask.getTitle()); + item->setText(1, getStatusLabel(editedTask.getStatusUUID())); + item->setText(2, getPriorityLabel(editedTask.getPriorityUUID())); + item->setText(3, editedTask.getExpectedFor().toString()); + + QBrush bgColor = item->background(1); + QBrush fgColor = item->foreground(1); + bgColor.setColor(getStatusColor(editedTask.getStatusUUID(), bgColor.color())); + bgColor.setStyle(Qt::BrushStyle::SolidPattern); + fgColor.setColor(Tools::getForegroundColor(bgColor.color())); + item->setBackground(1, bgColor); + item->setForeground(1, fgColor); + + bgColor = item->background(2); + fgColor = item->foreground(2); + bgColor.setColor(getPriorityColor(editedTask.getPriorityUUID(), bgColor.color())); + bgColor.setStyle(Qt::BrushStyle::SolidPattern); + fgColor.setColor(Tools::getForegroundColor(bgColor.color())); + item->setBackground(2, bgColor); + item->setForeground(2, fgColor); + } + } + } +} + +QVector MainWindow::defaultPriorities() +{ + QVector res; + res.append(Priority(QUuid::createUuid().toString(QUuid::WithoutBraces), "Low", QColor::fromString("#309db0"))); + res.append(Priority(QUuid::createUuid().toString(QUuid::WithoutBraces), "Medium", QColor::fromString("#b08e30"))); + res.append(Priority(QUuid::createUuid().toString(QUuid::WithoutBraces), "High", QColor::fromString("#b04330"))); + return res; +} + +QVector MainWindow::defaultStatus() +{ + QVector res; + res.append(Status(QUuid::createUuid().toString(QUuid::WithoutBraces), "To Do", QColor::fromString("#8f8f8f"))); + res.append(Status(QUuid::createUuid().toString(QUuid::WithoutBraces), "Working on", QColor::fromString("#5f30b0"))); + res.append(Status(QUuid::createUuid().toString(QUuid::WithoutBraces), "Completed", QColor::fromString("#30b049"))); + return res; +} + +const QString MainWindow::getPriorityLabel(QString uuid) +{ + QString res = ""; + foreach (Priority p, priorities) + { + if (p.getUUID() == uuid) + { + res = p.getName(); + } + } + return res; +} + +const QString MainWindow::getStatusLabel(QString uuid) +{ + QString res = ""; + foreach (Status s, status) + { + if (s.getUUID() == uuid) + { + res = s.getName(); + } + } + return res; +} + +const QColor MainWindow::getPriorityColor(QString uuid, QColor defaultColor) +{ + QColor color = defaultColor; + foreach (Priority p, priorities) + { + if (p.getUUID() == uuid) + { + color = p.getColor(); + } + } + return color; +} + +const QColor MainWindow::getStatusColor(QString uuid, QColor defaultColor) +{ + QColor color = defaultColor; + foreach (Status s, status) + { + if (s.getUUID() == uuid) + { + color = s.getColor(); + } + } + return color; +} + +void MainWindow::redrawBoardList() +{ + QListWidget *l = ui->listWidget; + for (int i = 0; i < l->count(); i++) + { + delete l->takeItem(i); + } + foreach (Board *b, boards) + { + QListWidgetItem *item = new QListWidgetItem(b->getName()); + l->addItem(item); + } +} + +void MainWindow::redrawTaskTree() +{ + QTreeWidget *l = ui->treeWidget; + for (int i = 0; i < l->topLevelItemCount(); i++) + { + delete l->takeTopLevelItem(i); + } + if (selectedBoardIndex > -1) + { + Board *b = boards[selectedBoardIndex]; + foreach (Task *t, b->getTasks()) + { + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setText(0, t->getTitle()); + item->setText(1, getStatusLabel(t->getStatusUUID())); + item->setText(2, getPriorityLabel(t->getPriorityUUID())); + item->setText(3, t->getExpectedFor().toString()); + + QBrush bgColor = item->background(1); + QBrush fgColor = item->foreground(1); + bgColor.setColor(getStatusColor(t->getStatusUUID(), bgColor.color())); + bgColor.setStyle(Qt::BrushStyle::SolidPattern); + fgColor.setColor(Tools::getForegroundColor(bgColor.color())); + item->setBackground(1, bgColor); + item->setForeground(1, fgColor); + + bgColor = item->background(2); + fgColor = item->foreground(2); + bgColor.setColor(getPriorityColor(t->getPriorityUUID(), bgColor.color())); + bgColor.setStyle(Qt::BrushStyle::SolidPattern); + fgColor.setColor(Tools::getForegroundColor(bgColor.color())); + item->setBackground(2, bgColor); + item->setForeground(2, fgColor); + + ui->treeWidget->addTopLevelItem(item); + } + } + +} + diff --git a/src/frames/mainwindow.h b/src/frames/mainwindow.h new file mode 100644 index 0000000..448c984 --- /dev/null +++ b/src/frames/mainwindow.h @@ -0,0 +1,52 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +#include "../models/priority.h" +#include "../models/status.h" +#include "../models/board.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private slots: + void openPreferences(); + void openAbout(); + void onNewBoardClick(); + void onNewTaskClick(); + void onBoardSelected(int i); + void onEditTask(QTreeWidgetItem*); + +private: + Ui::MainWindow *ui; + + int selectedBoardIndex = -1; + QVector priorities; + QVector status; + QVector boards; + + QVector defaultPriorities(); + QVector defaultStatus(); + + const QString getPriorityLabel(QString uuid); + const QString getStatusLabel(QString uuid); + + const QColor getPriorityColor(QString uuid, QColor defaultColor); + const QColor getStatusColor(QString uuid, QColor defaultColor); + + void redrawBoardList(); + void redrawTaskTree(); +}; +#endif // MAINWINDOW_H diff --git a/src/frames/mainwindow.ui b/src/frames/mainwindow.ui new file mode 100644 index 0000000..4ab4c3f --- /dev/null +++ b/src/frames/mainwindow.ui @@ -0,0 +1,154 @@ + + + MainWindow + + + + 0 + 0 + 1159 + 702 + + + + + 1159 + 702 + + + + TaskBoard + + + QTabWidget::Rounded + + + + + + + + + + 250 + 0 + + + + + 250 + 16777215 + + + + + + + + + + + 26 + + + + <- Select a board + + + + + + + true + + + 4 + + + + Name + + + + + Status + + + + + Priority + + + + + Expected for + + + + + + + + + + + + + + 0 + 0 + 1159 + 24 + + + + + About + + + + + + + + Board + + + + + + Task + + + + + + + + + + Preferences + + + + + New Board + + + + + About TaskBoard + + + + + false + + + New task + + + + + + diff --git a/src/frames/namedialog.cpp b/src/frames/namedialog.cpp new file mode 100644 index 0000000..0687bce --- /dev/null +++ b/src/frames/namedialog.cpp @@ -0,0 +1,25 @@ +#include "namedialog.h" +#include "ui_namedialog.h" + +NameDialog::NameDialog(QString label, QString defaultName, QWidget *parent) : + QDialog(parent), + ui(new Ui::NameDialog) +{ + ui->setupUi(this); + this->setWindowTitle(label); + this->defaultName = defaultName; +} + +NameDialog::~NameDialog() +{ + delete ui; +} + +const QString NameDialog::getChoosenName() +{ + if (ui->lineEdit->text().length() > 0) + { + return ui->lineEdit->text(); + } + return defaultName; +} diff --git a/src/frames/namedialog.h b/src/frames/namedialog.h new file mode 100644 index 0000000..0982c39 --- /dev/null +++ b/src/frames/namedialog.h @@ -0,0 +1,25 @@ +#ifndef NAMEDIALOG_H +#define NAMEDIALOG_H + +#include + +namespace Ui { +class NameDialog; +} + +class NameDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NameDialog(QString label, QString defaultName, QWidget *parent = nullptr); + ~NameDialog(); + const QString getChoosenName(); + +private: + Ui::NameDialog *ui; + + QString defaultName; +}; + +#endif // NAMEDIALOG_H diff --git a/src/frames/namedialog.ui b/src/frames/namedialog.ui new file mode 100644 index 0000000..41a3dff --- /dev/null +++ b/src/frames/namedialog.ui @@ -0,0 +1,109 @@ + + + NameDialog + + + Qt::WindowModal + + + + 0 + 0 + 400 + 133 + + + + + 400 + 133 + + + + + 400 + 133 + + + + Dialog + + + true + + + + + 40 + 90 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 50 + 381 + 21 + + + + + + + 10 + 30 + 58 + 16 + + + + Name + + + + + + + buttonBox + accepted() + NameDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NameDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/frames/prefdialog.cpp b/src/frames/prefdialog.cpp new file mode 100644 index 0000000..fedd8f9 --- /dev/null +++ b/src/frames/prefdialog.cpp @@ -0,0 +1,209 @@ +#include "prefdialog.h" +#include "ui_prefdialog.h" + +#include +#include + +#include "../tools.h" + +PrefDialog::PrefDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::PrefDialog) +{ + ui->setupUi(this); + connect(ui->addStatusButton, &QPushButton::clicked, this, &PrefDialog::onAddStatusButtonClick); + connect(ui->addPriorityButton, &QPushButton::clicked, this, &PrefDialog::onAddPriorityButtonClick); + connect(ui->statusListWidget, &QListWidget::currentRowChanged, this, &PrefDialog::onItemSelectionChange); + connect(ui->priorityListWidget, &QListWidget::currentRowChanged, this, &PrefDialog::onItemSelectionChange); + connect(ui->colorStatusButton, &QToolButton::clicked, this, &PrefDialog::onButtonColorButtonClick); + connect(ui->colorPriorityButton, &QToolButton::clicked, this, &PrefDialog::onButtonColorButtonClick); + connect(ui->nameStatusEdit, &QLineEdit::textEdited, this, &PrefDialog::onNameChange); + connect(ui->namePriorityEdit, &QLineEdit::textEdited, this, &PrefDialog::onNameChange); + connect(ui->removeStatusButton, &QPushButton::clicked, this, &PrefDialog::onRemoveStatusButtonClick); + connect(ui->removePriorityButton, &QPushButton::clicked, this, &PrefDialog::onRemovePriorityButtonClick); +} + +PrefDialog::~PrefDialog() +{ + delete ui; +} + +QVector PrefDialog::getPriorities() +{ + int count = ui->priorityListWidget->count(); + QVector res; + + for (int i = 0; i < count; i++) + { + QListWidgetItem *item = ui->priorityListWidget->item(i); + Priority p(priorityUUIDRef[i], item->text(), item->background().color()); + res.append(p); + } + + return res; +} + +QVector PrefDialog::getStatus() +{ + int count = ui->statusListWidget->count(); + QVector res; + + for (int i = 0; i < count; i++) + { + QListWidgetItem *item = ui->statusListWidget->item(i); + Status s(statusUUIDRef[i], item->text(), item->background().color()); + res.append(s); + } + + return res; +} + +void PrefDialog::onAddStatusButtonClick() +{ + QColor bgColor = Tools::getRandomColor(); + QListWidgetItem *item = new QListWidgetItem("New status"); + QUuid uuid = QUuid::createUuid(); + statusUUIDRef.append(uuid.toString(QUuid::WithoutBraces)); + + setItemColor(item, bgColor); + + ui->statusListWidget->addItem(item); +} + +void PrefDialog::onAddPriorityButtonClick() +{ + QColor bgColor = Tools::getRandomColor(); + QListWidgetItem *item = new QListWidgetItem("Low"); + QUuid uuid = QUuid::createUuid(); + priorityUUIDRef.append(uuid.toString(QUuid::WithoutBraces)); + + setItemColor(item, bgColor); + + ui->priorityListWidget->addItem(item); +} + +void PrefDialog::onItemSelectionChange(int index) +{ + QListWidget *listWidget = static_cast(QObject::sender()); + QPushButton *removeBtn; + QToolButton *colorBtn; + QLineEdit *nameEdit; + QLineEdit *colorEdit; + + if (listWidget == ui->statusListWidget) + { + removeBtn = ui->removeStatusButton; + colorBtn = ui->colorStatusButton; + nameEdit = ui->nameStatusEdit; + colorEdit = ui->colorStatusEdit; + } + else + { + removeBtn = ui->removePriorityButton; + colorBtn = ui->colorPriorityButton; + nameEdit = ui->namePriorityEdit; + colorEdit = ui->colorPriorityEdit; + } + bool d = (index == -1); + removeBtn->setDisabled(d); + colorBtn->setDisabled(d); + nameEdit->setDisabled(d); + colorEdit->setDisabled(d); + if (!d) + { + QListWidgetItem *current = listWidget->item(index); + nameEdit->setText(current->text()); + colorEdit->setText(current->background().color().name()); + } + else + { + nameEdit->clear(); + colorEdit->clear(); + } +} + +void PrefDialog::onButtonColorButtonClick() +{ + QColorDialog dialog(this); + if (dialog.exec() == DialogCode::Accepted) + { + QToolButton *sender = static_cast(QObject::sender()); + QLineEdit *colorEdit; + QListWidgetItem *item; + if (sender == ui->colorStatusButton) + { + colorEdit = ui->colorStatusEdit; + item = ui->statusListWidget->currentItem(); + } + else + { + colorEdit = ui->colorPriorityEdit; + item = ui->priorityListWidget->currentItem(); + } + QColor selectedColor = dialog.selectedColor(); + colorEdit->setText(selectedColor.name()); + setItemColor(item, selectedColor); + } +} + +void PrefDialog::onNameChange() +{ + QLineEdit *sender = static_cast(QObject::sender()); + QListWidgetItem *item; + if (sender == ui->nameStatusEdit) + { + if (ui->statusListWidget->selectedItems().size() != 1) + { + return; + } + item = ui->statusListWidget->currentItem(); + } + else + { + if (ui->priorityListWidget->selectedItems().size() != 1) + { + return; + } + item = ui->priorityListWidget->currentItem(); + } + item->setText(sender->text()); +} + +void PrefDialog::onRemoveStatusButtonClick() +{ + if (ui->statusListWidget->selectedItems().size() != 1) + { + return; + } + int index = ui->statusListWidget->currentRow(); + delete ui->statusListWidget->takeItem(index); + statusUUIDRef.removeAt(index); +} + +void PrefDialog::onRemovePriorityButtonClick() +{ + if (ui->priorityListWidget->selectedItems().size() != 1) + { + return; + } + int index = ui->priorityListWidget->currentRow(); + delete ui->priorityListWidget->takeItem(index); + priorityUUIDRef.removeAt(index); +} + +void PrefDialog::setItemColor(QListWidgetItem *item, QColor bgColor) +{ + QColor fgColor = Tools::getForegroundColor(bgColor); + + // Set background + QBrush bg = item->background(); + bg.setStyle(Qt::BrushStyle::SolidPattern); + bg.setColor(bgColor); + item->setBackground(bg); + + // Set foreground + QBrush fg = item->foreground(); + fg.setStyle(Qt::BrushStyle::SolidPattern); + fg.setColor(fgColor); + item->setForeground(fg); +} diff --git a/src/frames/prefdialog.h b/src/frames/prefdialog.h new file mode 100644 index 0000000..9e2c622 --- /dev/null +++ b/src/frames/prefdialog.h @@ -0,0 +1,44 @@ +#ifndef PREFDIALOG_H +#define PREFDIALOG_H + +#include +#include +#include + +#include "../models/priority.h" +#include "../models/status.h" + +namespace Ui { +class PrefDialog; +} + +class PrefDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PrefDialog(QWidget *parent = nullptr); + ~PrefDialog(); + + QVector getPriorities(); + QVector getStatus(); + +private slots: + void onAddStatusButtonClick(); + void onAddPriorityButtonClick(); + void onItemSelectionChange(int); + void onButtonColorButtonClick(); + void onNameChange(); + void onRemoveStatusButtonClick(); + void onRemovePriorityButtonClick(); + +private: + Ui::PrefDialog *ui; + + QVector statusUUIDRef; + QVector priorityUUIDRef; + + void setItemColor(QListWidgetItem*, QColor); +}; + +#endif // PREFDIALOG_H diff --git a/src/frames/prefdialog.ui b/src/frames/prefdialog.ui new file mode 100644 index 0000000..94dbc82 --- /dev/null +++ b/src/frames/prefdialog.ui @@ -0,0 +1,323 @@ + + + PrefDialog + + + Qt::ApplicationModal + + + + 0 + 0 + 655 + 535 + + + + + 655 + 535 + + + + + 655 + 535 + + + + Preferences + + + true + + + + + 300 + 490 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 10 + 631 + 471 + + + + 0 + + + + Status + + + + + 10 + 10 + 601 + 291 + + + + + + false + + + + 90 + 350 + 521 + 21 + + + + + + + 10 + 352 + 58 + 16 + + + + Name + + + + + + 10 + 390 + 58 + 16 + + + + Color + + + + + false + + + + 90 + 390 + 113 + 21 + + + + + + false + + + + 210 + 390 + 26 + 22 + + + + ... + + + + + + 570 + 300 + 41 + 32 + + + + + + + + + + false + + + + 520 + 300 + 41 + 32 + + + + - + + + + + + Priorities + + + + false + + + + 90 + 350 + 521 + 21 + + + + + + + 10 + 352 + 58 + 16 + + + + Name + + + + + false + + + + 90 + 390 + 113 + 21 + + + + + + + 10 + 10 + 601 + 291 + + + + + + + 10 + 390 + 58 + 16 + + + + Color + + + + + false + + + + 210 + 390 + 26 + 22 + + + + ... + + + + + + 570 + 300 + 41 + 32 + + + + + + + + + + false + + + + 520 + 300 + 41 + 32 + + + + - + + + + + + + + + buttonBox + accepted() + PrefDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PrefDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/frames/taskdialog.cpp b/src/frames/taskdialog.cpp new file mode 100644 index 0000000..4b8df8f --- /dev/null +++ b/src/frames/taskdialog.cpp @@ -0,0 +1,111 @@ +#include "taskdialog.h" +#include "ui_taskdialog.h" + +#include + +TaskDialog::TaskDialog(QVector status, QVector priorities, QWidget *parent) : + QDialog(parent), + ui(new Ui::TaskDialog) +{ + ui->setupUi(this); + this->setWindowTitle("New task"); + this->status = status; + this->priorities = priorities; + + foreach (Status s, this->status) + { + ui->statusCombo->addItem(s.getName()); + } + + foreach (Priority p, this->priorities) + { + ui->priorityCombo->addItem(p.getName()); + } + + QDate expectedFor = QDate::currentDate(); + expectedFor = expectedFor.addDays(10); + ui->expectedForEdit->setDate(expectedFor); +} + +TaskDialog::TaskDialog(Task *t, QVector status, QVector priorities, QWidget *parent) : + QDialog(parent), + ui(new Ui::TaskDialog) +{ + ui->setupUi(this); + this->setWindowTitle("Edit task"); + this->status = status; + this->priorities = priorities; + + foreach (Status s, this->status) + { + ui->statusCombo->addItem(s.getName()); + } + + foreach (Priority p, this->priorities) + { + ui->priorityCombo->addItem(p.getName()); + } + + // set fields + ui->nameEdit->setText(t->getTitle()); + ui->descriptionEdit->setMarkdown(t->getDescription()); + ui->expectedForEdit->setDate(t->getExpectedFor()); + + if (t->getPriorityUUID().length() > 0) + { + int refindex = -1; + for (int i = 0; i < this->priorities.count(); i++) + { + if (this->priorities[i].getUUID() == t->getPriorityUUID()) + { + refindex = i; + } + } + if (refindex > -1) + { + ui->priorityCombo->setCurrentIndex(refindex); + } + } + + if (t->getStatusUUID().length() > 0) + { + int refindex = -1; + for (int i = 0; i < this->status.count(); i++) + { + if (this->status[i].getUUID() == t->getStatusUUID()) + { + refindex = i; + } + } + if (refindex > -1) + { + ui->statusCombo->setCurrentIndex(refindex); + } + } + +} + +TaskDialog::~TaskDialog() +{ + delete ui; +} + +Task TaskDialog::getTask() +{ + QString title = ui->nameEdit->text(); + QString description = ui->descriptionEdit->toMarkdown(QTextDocument::MarkdownFeature::MarkdownDialectCommonMark); + QDate expectedFor = ui->expectedForEdit->date(); + QString priorityUUID = ""; + if (ui->priorityCombo->currentIndex() > -1) + { + Priority priority = priorities[ui->priorityCombo->currentIndex()]; + priorityUUID = priority.getUUID(); + } + QString statusUUID = ""; + if (ui->statusCombo->currentIndex() > -1) + { + Status s = status[ui->statusCombo->currentIndex()]; + statusUUID = s.getUUID(); + } + return Task(title, description, expectedFor, priorityUUID, statusUUID); +} diff --git a/src/frames/taskdialog.h b/src/frames/taskdialog.h new file mode 100644 index 0000000..f1fcb71 --- /dev/null +++ b/src/frames/taskdialog.h @@ -0,0 +1,33 @@ +#ifndef TASKDIALOG_H +#define TASKDIALOG_H + +#include +#include + +#include "../models/status.h" +#include "../models/priority.h" +#include "../models/task.h" + +namespace Ui { +class TaskDialog; +} + +class TaskDialog : public QDialog +{ + Q_OBJECT + +public: + explicit TaskDialog(QVector, QVector, QWidget *parent = nullptr); + TaskDialog(Task*, QVector, QVector, QWidget *parent = nullptr); + ~TaskDialog(); + + Task getTask(); + +private: + Ui::TaskDialog *ui; + + QVector status; + QVector priorities; +}; + +#endif // TASKDIALOG_H diff --git a/src/frames/taskdialog.ui b/src/frames/taskdialog.ui new file mode 100644 index 0000000..f155240 --- /dev/null +++ b/src/frames/taskdialog.ui @@ -0,0 +1,159 @@ + + + TaskDialog + + + Qt::WindowModal + + + + 0 + 0 + 481 + 557 + + + + + 481 + 557 + + + + Dialog + + + true + + + + + + + + Name + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + Description + + + + + + + + + + Qt::Horizontal + + + + + + + + + Expected for + + + + + + + + + + + + + + Status + + + + + + + + + + + + + + Priority + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + TaskDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TaskDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..8131678 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,11 @@ +#include "frames/mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/src/models/.DS_Store b/src/models/.DS_Store new file mode 100644 index 0000000..f876b0d Binary files /dev/null and b/src/models/.DS_Store differ diff --git a/src/models/board.cpp b/src/models/board.cpp new file mode 100644 index 0000000..9f99e34 --- /dev/null +++ b/src/models/board.cpp @@ -0,0 +1,40 @@ +#include "board.h" + +Board::Board(QString name) +{ + this->name = name; +} + +Board::~Board() +{ + for (int i = 0; i < tasks.count(); i++) + { + Task *t = tasks.takeAt(i); + delete t; + } +} + +const QString Board::getName() +{ + return name; +} + +void Board::add(Task t) +{ + tasks.append(new Task(t)); +} + +Task *Board::taskAt(int i) +{ + if (i >= 0 && i < tasks.count()) + { + return tasks[i]; + } + return nullptr; +} + +const QVector Board::getTasks() +{ + return tasks; +} + diff --git a/src/models/board.h b/src/models/board.h new file mode 100644 index 0000000..919c41d --- /dev/null +++ b/src/models/board.h @@ -0,0 +1,26 @@ +#ifndef BOARD_H +#define BOARD_H + +#include +#include + +#include "task.h" + +class Board +{ +public: + Board(QString name); + ~Board(); + + const QString getName(); + void add(Task); + Task *taskAt(int); + const QVector getTasks(); + +private: + QVector tasks; + QString name; + +}; + +#endif // BOARD_H diff --git a/src/models/priority.cpp b/src/models/priority.cpp new file mode 100644 index 0000000..2507636 --- /dev/null +++ b/src/models/priority.cpp @@ -0,0 +1,23 @@ +#include "priority.h" + +Priority::Priority(QString uuid, QString name, QColor color) +{ + this->uuid = uuid; + this->name = name; + this->color = color; +} + +const QString Priority::getName() +{ + return this->name; +} + +const QString Priority::getUUID() +{ + return this->uuid; +} + +const QColor Priority::getColor() +{ + return this->color; +} diff --git a/src/models/priority.h b/src/models/priority.h new file mode 100644 index 0000000..63a1e5b --- /dev/null +++ b/src/models/priority.h @@ -0,0 +1,23 @@ +#ifndef PRIORITY_H +#define PRIORITY_H + +#include +#include + +class Priority +{ +public: + Priority(QString uuid, QString name, QColor color); + + const QString getName(); + const QString getUUID(); + const QColor getColor(); + +private: + QString uuid; + QString name; + QColor color; + +}; + +#endif // PRIORITY_H diff --git a/src/models/status.cpp b/src/models/status.cpp new file mode 100644 index 0000000..0bce06b --- /dev/null +++ b/src/models/status.cpp @@ -0,0 +1,23 @@ +#include "status.h" + +Status::Status(QString uuid, QString name, QColor color) +{ + this->uuid = uuid; + this->name = name; + this->color = color; +} + +const QString Status::getName() +{ + return this->name; +} + +const QString Status::getUUID() +{ + return this->uuid; +} + +const QColor Status::getColor() +{ + return this->color; +} diff --git a/src/models/status.h b/src/models/status.h new file mode 100644 index 0000000..e4d7fc1 --- /dev/null +++ b/src/models/status.h @@ -0,0 +1,22 @@ +#ifndef STATUS_H +#define STATUS_H + +#include +#include + +class Status +{ +public: + Status(QString uuid, QString name, QColor color); + + const QString getName(); + const QString getUUID(); + const QColor getColor(); + +private: + QString uuid; + QString name; + QColor color; +}; + +#endif // STATUS_H diff --git a/src/models/task.cpp b/src/models/task.cpp new file mode 100644 index 0000000..7d56906 --- /dev/null +++ b/src/models/task.cpp @@ -0,0 +1,44 @@ +#include "task.h" + +Task::Task(QString title, QString description, QDate expectedFor, QString priorityUUID, QString statusUUID) +{ + this->title = title; + this->description = description; + this->expectedFor = expectedFor; + this->priorityUUID = priorityUUID; + this->statusUUID = statusUUID; +} + +const QString Task::getTitle() +{ + return this->title; +} + +const QString Task::getDescription() +{ + return this->description; +} + +const QDate Task::getExpectedFor() +{ + return this->expectedFor; +} + +const QString Task::getPriorityUUID() +{ + return this->priorityUUID; +} + +const QString Task::getStatusUUID() +{ + return this->statusUUID; +} + +void Task::update(Task t) +{ + this->title = t.title; + this->description = t.description; + this->expectedFor = t.expectedFor; + this->priorityUUID = t.priorityUUID; + this->statusUUID = t.statusUUID; +} diff --git a/src/models/task.h b/src/models/task.h new file mode 100644 index 0000000..75606e3 --- /dev/null +++ b/src/models/task.h @@ -0,0 +1,28 @@ +#ifndef TASK_H +#define TASK_H + +#include +#include + +class Task +{ +public: + Task(QString title, QString description, QDate expectedFor, QString priorityUUID, QString statusUUID); + + const QString getTitle(); + const QString getDescription(); + const QDate getExpectedFor(); + const QString getPriorityUUID(); + const QString getStatusUUID(); + + void update(Task); + +private: + QString title; + QString description; + QDate expectedFor; + QString priorityUUID; + QString statusUUID; +}; + +#endif // TASK_H diff --git a/src/tools.cpp b/src/tools.cpp new file mode 100644 index 0000000..30135be --- /dev/null +++ b/src/tools.cpp @@ -0,0 +1,48 @@ +#include "tools.h" + +#define BRIGHTNESS_THRESHOLD 170 +#define WHITECOLOR 240 +#define BLACKCOLOR 15 + +Tools::Tools() +{ + +} + +QColor Tools::getRandomColor() +{ + srand(time(0)); + int r = arc4random() % 255; + int g = arc4random() % 255; + int b = arc4random() % 255; + return QColor(r, g, b); +} + +QColor Tools::getForegroundColor(QColor background) +{ + int avg = background.red(); + avg += background.green(); + avg += background.blue(); + avg = avg / 3; + + int avg2 = background.red(); + avg2 += background.green(); + avg2 = avg2 / 2; + + int avg3 = background.red(); + avg3 += background.blue(); + avg3 = avg3 / 2; + + int avg4 = background.green(); + avg4 += background.blue(); + avg4 = avg4 / 2; + + if (avg < BRIGHTNESS_THRESHOLD && avg2 < BRIGHTNESS_THRESHOLD && avg3 < BRIGHTNESS_THRESHOLD && avg4 < BRIGHTNESS_THRESHOLD) + { + return QColor(WHITECOLOR, WHITECOLOR, WHITECOLOR); + } + else + { + return QColor(BLACKCOLOR, BLACKCOLOR, BLACKCOLOR); + } +} diff --git a/src/tools.h b/src/tools.h new file mode 100644 index 0000000..97e0e22 --- /dev/null +++ b/src/tools.h @@ -0,0 +1,16 @@ +#ifndef TOOLS_H +#define TOOLS_H + +#include + +class Tools +{ +public: + Tools(); + + static QColor getRandomColor(); + static QColor getForegroundColor(QColor background); + +}; + +#endif // TOOLS_H