Compare commits

...

7 Commits

Author SHA1 Message Date
9f43833cb1 Added a new QML file for UserConfiguration and also the initial
implementation for a CalendarGrid
2025-11-16 17:26:00 +02:00
d5e742155f Added new resource files, changed the CMake configuration to always
rebuild the resources files and also added the first main window to the
interface
2025-08-30 18:27:49 +03:00
2b662e58ab Restylized the button by changing its size and text alignment properties 2025-03-03 22:18:11 +02:00
1793f5b949 Added a new custom Button component 2025-02-08 01:17:11 +02:00
d479a5e242 Implemented JSON serialization
Added new iterator and const_iterator objects to UserList and also
implemented the serialization function to write to a JSON file
2025-02-07 23:06:27 +02:00
09b1e17de0 Implemented error checks for parsing the JSON file 2025-02-07 20:20:04 +02:00
a458d82577 Refactored code and possibly fixed a bug 2025-02-07 20:13:30 +02:00
15 changed files with 480 additions and 26 deletions

View File

@@ -0,0 +1,42 @@
import QtQuick
import QtQuick.Controls
Rectangle
{
width: parent.width
height: 50
color: "black"
Button
{
id: setDefaultButton
icon.source: "qrc:/resources/tick.svg"
icon.width: 40
icon.height: 40
icon.color: "transparent"
width: 50
height: parent.height - 4
anchors.right: createNewUserButton.left
}
Button
{
id: createNewUserButton
icon.source: "qrc:/resources/user.svg"
icon.width: 40
icon.height: 40
icon.color: "transparent"
width: 50
height: parent.height - 4
anchors.right: parent.right
onClicked: userConfiguration.open()
}
UserConfiguration
{
id: userConfiguration
}
}

View File

@@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.16)
project(Project-Orion VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTORCC ON)
find_package(Qt6 REQUIRED COMPONENTS Quick)
@@ -21,6 +22,11 @@ qt_add_qml_module(appProject-Orion
SOURCES userlist.h userlist.cpp
SOURCES serialization.h
SOURCES serialization.cpp
QML_FILES CustomButton.qml
QML_FILES Appheader.qml
RESOURCES resources.qrc
QML_FILES CalendarGrid.qml
QML_FILES UserConfiguration.qml
)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.

View File

@@ -0,0 +1,48 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
GridLayout {
columns: 2
DayOfWeekRow {
locale: grid.locale
Layout.column: 1
Layout.fillWidth: true
}
WeekNumberColumn {
month: grid.month
year: grid.year
locale: grid.locale
Layout.fillHeight: true
delegate: Text {
text: weekNumber
font: control.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: myPalette.text
required property int weekNumber
}
}
MonthGrid {
id: grid
month: Calendar.November
year: 2025
locale: Qt.locale("en_US")
Layout.fillWidth: true
Layout.fillHeight: true
delegate: Text {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
opacity: model.month === monthGrid.month ? 1 : 0
text: monthGrid.locale.toString(model.date, "d")
font: monthGrid.font
required property var model
}
}
}

View File

@@ -0,0 +1,33 @@
import QtQuick
Rectangle {
id: button
property string text: "<placeholder>"
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
width: parent.width * 0.25
height: parent.height * 0.1
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: clickablearea.pressed ? "dimgrey" : "gray"
radius: 2
Text
{
color: myPalette.buttonText
text: button.text
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignHCenter
width: parent.width
wrapMode: Text.Wrap
}
MouseArea
{
id: clickablearea
anchors.fill: parent
onClicked: { console.error("Hehehe") }
}
}

View File

@@ -1,23 +1,39 @@
import QtQuick
import QtQuick.Layouts
Window {
width: 640
height: 480
visible: true
title: qsTr("Lifespan viewer")
title: "Lifespan viewer"
minimumWidth: 200
minimumHeight: 150
Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
color: myPalette.window
id: name
Text {
id: emptyText
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("This view is currently empty :(")
height: parent.height
Appheader
{
id: myHeader
}
GridLayout {
id: grid
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.top: myHeader.bottom
anchors.leftMargin: 10
columns: 10
Repeater {
model: 30
Rectangle {
width: 30; height: 30
radius: 50
border.width: 1
color: "green"
}
}
}
}

View File

@@ -0,0 +1,44 @@
import QtQuick
import QtQuick.Controls
Dialog {
id: dialog
modal: true
title: "Configure a new user"
width: 600
height: 400
Row {
id: usernameRow
spacing: 100
Label {
id: nameFieldLabel
text: qsTr("Username:")
}
TextField {
id: nameField
color: myPalette.text
width: 400
placeholderText: "Enter the new user's username"
}
}
Row {
id: dateOfBirthRow
anchors.top: usernameRow.bottom
spacing: 100
Label {
id: dateOfBirthLabel
text: qsTr("Date of birth:")
}
CalendarGrid {
id: dateOfBirthGrid
}
}
standardButtons: Dialog.Ok | Dialog.Cancel
}

View File

@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/resources">
<file>user.svg</file>
<file>tick.svg</file>
</qresource>
<qresource prefix="/"/>
</RCC>

View File

@@ -5,31 +5,57 @@
#include <QJsonArray>
#include <QJsonObject>
UserList&& loadUserList(const QString &file)
UserList loadUserList(const QString &file)
{
QFile doc{std::filesystem::path{file.toStdString()}};
doc.open(QFile::ReadOnly);
QString fileContents = doc.readAll();
QJsonDocument document = QJsonDocument::fromJson(fileContents.toUtf8());
QJsonParseError errors;
QJsonDocument document =
QJsonDocument::fromJson(fileContents.toUtf8(),
&errors);
if (document.isNull())
{
qDebug() << errors.errorString();
throw std::runtime_error{"Could not parse JSON file"};
}
QJsonArray array = document.array();
QVector<User> container;
for (auto elem: array)
for (QJsonArray::const_iterator elem = array.constBegin(); elem != array.constEnd(); ++elem)
{
auto obj = elem.toObject();
User newUser{obj["name"].toString(), QDate::fromString(obj["date_of_birth"].toString()),
QDate::fromString(obj["date_of_death"].toString()), obj["default"].toBool()};
auto obj = elem->toObject();
User newUser{obj[NAME_LABEL].toString(), QDate::fromString(obj[DATE_OF_BIRTH_LABEL].toString()),
QDate::fromString(obj[DATE_OF_DEATH_LABEL].toString()), obj[DEFAULT_LABEL].toBool()};
container.append(newUser);
}
UserList returnObj;
returnObj.setList(container);
return std::move(returnObj);
return container;
}
void saveUserList(const UserList &list)
void saveUserList(const UserList &list, const QString &file)
{
QFile doc{std::filesystem::path{file.toStdString()}};
doc.open(QFile::WriteOnly);
QJsonArray container;
for(auto &obj: list)
{
QJsonObject newObject;
newObject[NAME_LABEL] = obj.getName();
newObject[DATE_OF_BIRTH_LABEL] = obj.getDateOfBirth().toString();
newObject[DATE_OF_DEATH_LABEL] = obj.getDateOfDeath().toString();
newObject[DEFAULT_LABEL] = obj.getIsItDefault();
container.append(newObject);
}
QJsonDocument document{container};
doc.write(document.toJson());
}

View File

@@ -1,9 +1,14 @@
#ifndef SERIALIZATION_H
#define SERIALIZATION_H
#define NAME_LABEL "name"
#define DATE_OF_BIRTH_LABEL "date_of_birth"
#define DATE_OF_DEATH_LABEL "date_of_death"
#define DEFAULT_LABEL "default"
#include "userlist.h"
UserList &&loadUserList(const QString &file);
void saveUserList(const UserList &list);
UserList loadUserList(const QString &file);
void saveUserList(const UserList &list, const QString &file);
#endif // SERIALIZATION_H

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="392.23944"
height="352.99045"
viewBox="0 0 392.23944 352.99045"
version="1.1"
id="svg1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px">
<inkscape:page
x="0"
y="0"
width="392.23944"
height="352.99045"
id="page2"
margin="0"
bleed="0" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-79.920158,-79.249199)">
<path
style="fill:#15ff00;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 80.40236,163.66999 153.77586,431.26747 471.43996,106.69762 442.09056,79.937873 166.79688,350.99382 Z"
id="path1"
sodipodi:nodetypes="cccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -3,3 +3,43 @@
User::User(QString name, QDate dateOfBirth, QDate dateOfDeath, bool isItDefault)
: name{name}, dateOfBirth{dateOfBirth}, dateOfDeath{dateOfDeath}, isItDefault{isItDefault}
{}
QString User::getName() const
{
return name;
}
void User::setName(const QString &newName)
{
name = newName;
}
QDate User::getDateOfBirth() const
{
return dateOfBirth;
}
void User::setDateOfBirth(const QDate &newDateOfBirth)
{
dateOfBirth = newDateOfBirth;
}
QDate User::getDateOfDeath() const
{
return dateOfDeath;
}
void User::setDateOfDeath(const QDate &newDateOfDeath)
{
dateOfDeath = newDateOfDeath;
}
bool User::getIsItDefault() const
{
return isItDefault;
}
void User::setIsItDefault(bool newIsItDefault)
{
isItDefault = newIsItDefault;
}

View File

@@ -7,6 +7,18 @@ class User
public:
User(QString name, QDate dateOfBirth, QDate dateOfDeath, bool isItDefault = false);
QString getName() const;
void setName(const QString &newName);
QDate getDateOfBirth() const;
void setDateOfBirth(const QDate &newDateOfBirth);
QDate getDateOfDeath() const;
void setDateOfDeath(const QDate &newDateOfDeath);
bool getIsItDefault() const;
void setIsItDefault(bool newIsItDefault);
private:
QString name;
QDate dateOfBirth;

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="125.8321mm"
height="92.671555mm"
viewBox="0 0 125.8321 92.671555"
version="1.1"
id="svg1"
sodipodi:docname="user.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="1.7044739"
inkscape:cx="237.90332"
inkscape:cy="175.12735"
inkscape:window-width="1440"
inkscape:window-height="832"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:page
x="-4.7078728e-14"
y="0"
width="125.83211"
height="92.671555"
id="page2"
margin="0"
bleed="0" />
</sodipodi:namedview>
<defs
id="defs1" />
<path
id="path2"
style="fill:#000000;stroke-width:2.47253"
d="M 58.57937,60.880724 A 70.353088,70.353088 0 0 0 2.4080776e-6,92.272604 H 117.15926 A 70.353088,70.353088 0 0 0 58.57937,60.880724 Z" />
<path
id="path3"
style="fill:#000000;stroke-width:2.47253"
d="m 115.06636,16.559916 a 10.765774,63.092445 0 0 0 -10.76575,63.092278 10.765774,63.092445 0 0 0 0.23151,13.01936 h 21.06797 a 10.765774,63.092445 0 0 0 0.23202,-13.01936 10.765774,63.092445 0 0 0 -10.76575,-63.092278 z" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-46.42042,-54.043526)">
<circle
style="fill:#000000;stroke-width:2.47253"
id="path1"
cx="105"
cy="82.255211"
r="25.036684" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1,6 +1,8 @@
#include "userlist.h"
UserList::UserList() {}
UserList::UserList(const QVector<User> &list):
list{list}
{}
QVector<User> UserList::getList() const
{

View File

@@ -5,15 +5,76 @@
#include <QObject>
class UserList: public QObject
class UserList : public QObject
{
Q_OBJECT
public:
UserList();
UserList(const QVector<User> &list);
QVector<User> getList() const;
void setList(const QVector<User> &newList);
struct iteratable
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = User;
using pointer = User *; // or also value_type*
using reference = User&; // or also value_type&
iteratable(User *begin)
: ptr{begin}
{}
reference operator*() const { return *ptr; }
pointer operator->() { return ptr; }
// Prefix increment
iteratable& operator++() { ptr++; return *this; }
// Postfix increment
iteratable operator++(int) { iteratable tmp = *this; ++(*this); return tmp; }
friend bool operator== (const iteratable& a, const iteratable& b) { return a.ptr == b.ptr; };
friend bool operator!= (const iteratable& a, const iteratable& b) { return a.ptr != b.ptr; };
private:
User* ptr;
};
struct const_interatable
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = const User;
using pointer = const User *; // or also value_type*
using reference = const User&; // or also value_type&
const_interatable(const User *begin)
: ptr{begin}
{}
reference operator*() const { return *ptr; }
pointer operator->() { return ptr; }
// Prefix increment
const_interatable& operator++() { ptr++; return *this; }
// Postfix increment
const_interatable operator++(int) { const_interatable tmp = *this; ++(*this); return tmp; }
friend bool operator== (const const_interatable& a, const const_interatable& b) { return a.ptr == b.ptr; };
friend bool operator!= (const const_interatable& a, const const_interatable& b) { return a.ptr != b.ptr; };
private:
const User* ptr;
};
iteratable begin() { return &*list.begin(); }
iteratable end() { return &*list.end(); }
const_interatable begin() const { return &*list.begin(); }
const_interatable end() const { return &*list.end(); }
private:
QVector<User> list;
};