From 523a4085cc6252e5680bb87e3d6d6d3228689161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lie=20DELHAIE?= Date: Sat, 14 Mar 2026 05:27:54 +0100 Subject: [PATCH] first commit --- .gitignore | 84 ++++++++++++++ ToDo.pro | 97 ++++++++++++++++ ToDo_en_150.ts | 3 + dialog.cpp | 36 ++++++ dialog.h | 29 +++++ dialog.ui | 186 +++++++++++++++++++++++++++++ list.cpp | 34 ++++++ list.h | 26 +++++ listservice.cpp | 50 ++++++++ listservice.h | 37 ++++++ main.cpp | 23 ++++ mainwindow.cpp | 54 +++++++++ mainwindow.h | 29 +++++ mainwindow.ui | 303 ++++++++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 991 insertions(+) create mode 100644 .gitignore create mode 100644 ToDo.pro create mode 100644 ToDo_en_150.ts create mode 100644 dialog.cpp create mode 100644 dialog.h create mode 100644 dialog.ui create mode 100644 list.cpp create mode 100644 list.h create mode 100644 listservice.cpp create mode 100644 listservice.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca8b61e --- /dev/null +++ b/.gitignore @@ -0,0 +1,84 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash +**/.qmlls.ini + +# qtcreator generated files +*.pro.user* +*.qbs.user* +CMakeLists.txt.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + +# Directories with generated files +.moc/ +.obj/ +.pch/ +.rcc/ +.uic/ +/build*/ +/.qtcreator/ diff --git a/ToDo.pro b/ToDo.pro new file mode 100644 index 0000000..a5fb6bc --- /dev/null +++ b/ToDo.pro @@ -0,0 +1,97 @@ +QT += widgets + +CONFIG += c++17 + +QMAKE_CXXFLAGS += -Wall -Wextra -Wpedantic +QMAKE_CXXFLAGS += -Werror + +win32:VERSION = 3.0.0.0 # major.minor.patch.build +else:VERSION = 3.0.0 # major.minor.patch + +DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\" +DEFINES += APP_NAME=\"\\\"ToDo\\\"\" + +# remove possible other optimization flags +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 = "ToDo" + QMAKE_TARGET_DESCRIPTION = "ToDo" +} + +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 = 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 += \ + dialog.cpp \ + list.cpp \ + listservice.cpp \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + dialog.h \ + list.h \ + listservice.h \ + mainwindow.h + +FORMS += \ + dialog.ui \ + mainwindow.ui + +TRANSLATIONS += \ + ToDo_en_150.ts +CONFIG += lrelease +CONFIG += embed_translations + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/ToDo_en_150.ts b/ToDo_en_150.ts new file mode 100644 index 0000000..0bdd0ba --- /dev/null +++ b/ToDo_en_150.ts @@ -0,0 +1,3 @@ + + + diff --git a/dialog.cpp b/dialog.cpp new file mode 100644 index 0000000..9691ab1 --- /dev/null +++ b/dialog.cpp @@ -0,0 +1,36 @@ +#include "dialog.h" +#include "ui_dialog.h" + +Dialog::Dialog(QWidget *parent, QString title, QString headline, QString message) : QDialog(parent), ui(new Ui::Dialog) +{ + ui->setupUi(this); + this->setWindowTitle(title); + ui->headline->setText(headline); + ui->message->setText(message); +} + +Dialog::~Dialog() +{ + delete ui; +} + +QString Dialog::getInput() +{ + if (this->result() != Accepted) { + return ""; + } + return this->ui->lineEdit->text(); +} + + +void Dialog::on_buttonBox_accepted() +{ + accept(); +} + + +void Dialog::on_buttonBox_rejected() +{ + reject(); +} + diff --git a/dialog.h b/dialog.h new file mode 100644 index 0000000..9a7b9ab --- /dev/null +++ b/dialog.h @@ -0,0 +1,29 @@ +#ifndef DIALOG_H +#define DIALOG_H + +#include + +namespace Ui { +class Dialog; +} + +class Dialog : public QDialog +{ + Q_OBJECT + +public: + Dialog(QWidget *parent, QString title, QString headline, QString message); + ~Dialog(); + + QString getInput(); + +private slots: + void on_buttonBox_accepted(); + + void on_buttonBox_rejected(); + +private: + Ui::Dialog *ui; +}; + +#endif // DIALOG_H diff --git a/dialog.ui b/dialog.ui new file mode 100644 index 0000000..549d341 --- /dev/null +++ b/dialog.ui @@ -0,0 +1,186 @@ + + + Dialog + + + Qt::WindowModality::ApplicationModal + + + + 0 + 0 + 454 + 176 + + + + + 454 + 176 + + + + + 454 + 176 + + + + Dialog + + + background-color: rgb(249, 255, 251); + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + QLayout::SizeConstraint::SetDefaultConstraint + + + + + + 16777215 + 50 + + + + + 22 + Light + + + + background-color: rgb(138, 176, 106); +padding: 6px; +padding-left: 20 px; +padding-right: 20px; + + + + + + + + + + + 16777215 + 40 + + + + color: rgb(13, 13, 13); +padding: 6px; +padding-left: 20px; +padding-right: 20px; + + + + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop + + + + + + + margin: 6px; +margin-left: 20px; +margin-right: 20px; +background-color: rgb(243, 243, 243); +padding: 4px; +color: rgb(13, 13, 13); +border: 2px solid rgb(230, 230, 230); + + + + + + + 0 + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 30 + + + + + + + + QPushButton { + border: none; + color: rgb(12, 12, 12); + background-color: rgb(217, 217, 217); + padding: 6px; +} + +QPushButton::pressed { + background-color: ; + background-color: rgb(192, 192, 192); +} + + + QDialogButtonBox::StandardButton::Discard|QDialogButtonBox::StandardButton::Save + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 30 + + + + + + + + + + + + + diff --git a/list.cpp b/list.cpp new file mode 100644 index 0000000..2af90a6 --- /dev/null +++ b/list.cpp @@ -0,0 +1,34 @@ +#include "list.h" + +List::List(QUuid uuid, QString name) +{ + this->uuid = uuid; + this->name = name; +} + +List::List(QString name) +{ + this->uuid = QUuid::createUuid(); + this->name = name; +} + +QUuid List::getUUID() +{ + return this->uuid; +} + +QString List::getName() +{ + return this->name; +} + +void List::setName(QString value) +{ + this->name = value; +} + +List List::duplicate() +{ + List l = List(this->getName() + " (copy)"); + return l; +} diff --git a/list.h b/list.h new file mode 100644 index 0000000..b3e9e3a --- /dev/null +++ b/list.h @@ -0,0 +1,26 @@ +#ifndef LIST_H +#define LIST_H + +#include +#include + +class List +{ +private: + QUuid uuid; + QString name; + +public: + List() {} + List(QUuid uuid, QString name); + List(QString name); + + QUuid getUUID(); + QString getName(); + + void setName(QString value); + List duplicate(); + +}; + +#endif // LIST_H diff --git a/listservice.cpp b/listservice.cpp new file mode 100644 index 0000000..23b0a3b --- /dev/null +++ b/listservice.cpp @@ -0,0 +1,50 @@ +#include "listservice.h" + +ListService* ListService::_instance = nullptr; + +ListService::ListService() {} + +ListService *ListService::getInstance() +{ + if (_instance == nullptr) { + _instance = new ListService(); + } + + return _instance; +} + +List ListService::create(QString name) +{ + // create the object, the uuid is already assigned by itself + List l = List(name); + + // store + // TODO: implement the real datastore (SQLite or something like that) + this->store[l.getUUID().toUInt128()] = l; + + // return the actual value + onListCreated(l); + return l; +} + +List ListService::update(QUuid uuid, QString newName) +{ + if (!this->store.contains(uuid.toUInt128())) { + throw new std::exception(); + } + + List l = this->store.value(uuid.toUInt128(), List("!!!")); + l.setName(newName); + this->store[uuid.toUInt128()] = l; + + onListUpdated(l); + return l; +} + +void ListService::remove(QUuid uuid) +{ + this->store.remove(uuid.toUInt128()); + onListDeleted(uuid); +} + + diff --git a/listservice.h b/listservice.h new file mode 100644 index 0000000..7a7ea35 --- /dev/null +++ b/listservice.h @@ -0,0 +1,37 @@ +#ifndef LISTSERVICE_H +#define LISTSERVICE_H + +#include +#include + +#include "list.h" + +/* + * + * ListService is a singleton that query the "lists" over the datasource layer + * + */ +class ListService : public QObject +{ + Q_OBJECT +private: + ListService(); + static ListService* _instance; + + QMap store; + +public: + static ListService* getInstance(); + + List create(QString name); + List update(QUuid uuid, QString newName); + void remove(QUuid uuid); + +signals: + void onListCreated(List value); + void onListUpdated(List value); + void onListDeleted(QUuid uuid); + +}; + +#endif // LISTSERVICE_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..43b7ce9 --- /dev/null +++ b/main.cpp @@ -0,0 +1,23 @@ +#include "mainwindow.h" + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QTranslator translator; + const QStringList uiLanguages = QLocale::system().uiLanguages(); + for (const QString &locale : uiLanguages) { + const QString baseName = "ToDo_" + QLocale(locale).name(); + if (translator.load(":/i18n/" + baseName)) { + a.installTranslator(&translator); + break; + } + } + MainWindow w; + w.show(); + return QCoreApplication::exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..3b56b2e --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,54 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "dialog.h" +#include "listservice.h" + +#include +#include + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + /* + * Events + */ + + // ui + connect(ui->addListButton, &QPushButton::clicked, this, &MainWindow::openCreateListDialog); + + // services + connect(ListService::getInstance(), &ListService::onListCreated, this, &MainWindow::onListCreated); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::openCreateListDialog(bool _) +{ + // create the input dialog + Dialog d = Dialog(this, "Create a list", "New List", "Give a name to this list"); + auto res = d.exec(); + + // execute, ignore if not saved + if (res != QDialog::Accepted) { + return; + } + + QString newListName = d.getInput(); + ListService::getInstance()->create(newListName); +} + +void MainWindow::onListCreated(List value) +{ + QListWidgetItem* item = new QListWidgetItem(); + item->setText(value.getName()); + item->setData(Qt::UserRole, QVariant(value.getUUID())); + + this->ui->lists->addItem(item); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..b12489a --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,29 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include "list.h" + +QT_BEGIN_NAMESPACE +namespace Ui { +class MainWindow; +} +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow() override; + +private slots: + void openCreateListDialog(bool); + void onListCreated(List value); + +private: + Ui::MainWindow *ui; + +}; +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..363818d --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,303 @@ + + + MainWindow + + + + 0 + 0 + 1032 + 629 + + + + + 1032 + 629 + + + + MainWindow + + + background-color: rgb(249, 255, 251); + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + QLayout::SizeConstraint::SetDefaultConstraint + + + + + + 250 + 50 + + + + + 250 + 50 + + + + + 28 + DemiBold + + + + background-color: rgb(119, 167, 92); +border: none; +padding-left: 2px; +border-bottom: 2px solid rgb(242, 242, 242) + + + 0 + + + ToDo + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter + + + + + + + + 250 + 0 + + + + + 250 + 16777215 + + + + + 15 + Light + + + + QListView { + show-decoration-selected: 1; /* make the selection span the entire width of the view */ + background-color: rgb(119, 167, 92); + border: none; + padding: 2px; + padding-top: 14px; +} + +QListView::item { + padding: 8px; + border: none; +} + +QListView::item:selected { + background-color: rgb(170, 216, 130); +} + +QListView::item:selected:!active { + background: none; +} + +QListView::item:selected:active { + background-color: rgb(170, 216, 130); +} + +QListView::item:hover { + background-color: rgb(152, 193, 116); +} + + + QFrame::Shadow::Plain + + + 0 + + + 2 + + + QAbstractItemView::EditTrigger::NoEditTriggers + + + false + + + Qt::DropAction::IgnoreAction + + + Qt::DropAction::IgnoreAction + + + + + + + + 250 + 0 + + + + + 250 + 16777215 + + + + background-color: rgb(138, 176, 106); + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + border: none; +padding: 6px; + + + + + + + + + true + + + + + + + + + + + + false + + + QListView { + show-decoration-selected: 1; /* make the selection span the entire width of the view */ + background-color: rgb(242, 242, 242); + border: none; + padding: 2px; + color: rgb(13, 13, 13); +} + +QListView::item { + margin: 2px; + padding: 8px; + border: none; +} + +QListView::item:alternate { + background: #EEEEEE; +} + +QListView::item:selected { + background-color: rgb(154, 154, 154); +} + +QListView::item:selected:!active { + background: none; +} + +QListView::item:selected:active { + background-color: rgb(154, 154, 154); +} + +QListView::item:hover { + background-color: rgb(204, 204, 204); +} + + + QFrame::Shadow::Plain + + + 0 + + + QAbstractItemView::EditTrigger::NoEditTriggers + + + false + + + Qt::DropAction::IgnoreAction + + + QAbstractItemView::SelectionMode::NoSelection + + + Qt::DropAction::IgnoreAction + + + + + + + + + + +