Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
489df44
merge: merge_ui_parts into main, MVP implementation
mirotvoretts Apr 5, 2025
4114823
docs: update installation guide and add screenshot
mirotvoretts Apr 5, 2025
3d06e25
docs: update building app guide
mirotvoretts Apr 10, 2025
d0736d3
Merge pull request #8 from toximu/proto
toximu Apr 10, 2025
69edfb7
return main.cpp
toximu Apr 10, 2025
34b3b8d
Changes in login_window style: add 4 new themes, but have bug because…
MuravAna Apr 11, 2025
e7c2a9a
Update of themes in AutorizationWindows and MainWindow
MuravAna Apr 11, 2025
d662459
All of the styles for all of the windows work correctlybut without sa…
MuravAna Apr 15, 2025
c083ed0
resolve conflicts, trying add new styles
MuravAna Apr 15, 2025
7440881
Fix bug with double messages after press buttons in autorization's wi…
MuravAna Apr 15, 2025
c698ca3
Implement profile and settings windows. Complete profile window, sett…
MuravAna May 8, 2025
8f2ec58
Add part-realization of analytics window
MuravAna May 12, 2025
9fffd9a
Add analytics window (raw yet). Fix bugs in style, add base for trans…
MuravAna May 16, 2025
1a0d814
Add ability to change font-size in all windows via settings
MuravAna May 18, 2025
be5f985
Add ability to change language in all windows
MuravAna May 19, 2025
c15c578
Add language button iin autorizations window. Fix bug in main window …
MuravAna Jun 3, 2025
43e671c
Delete switch_theme_button, add delete_button
MuravAna Jun 3, 2025
d4ba50e
Delete delete_button
MuravAna Jun 3, 2025
4279857
Add draft of types of notes
MuravAna Jun 8, 2025
43b749a
feat: display project name in note edit window
mirotvoretts Jun 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ build-*
*/build-*
release/
debug/
protobuf/
*.exe
*.dll
*.so
Expand All @@ -12,6 +13,7 @@ debug/
*.o
*.obj
*.app
translations/*.qm

moc_*.cpp
ui_*.h
Expand Down
12 changes: 11 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ find_package(Qt6 COMPONENTS Widgets Core Gui Sql REQUIRED)

add_subdirectory(scripts)
add_subdirectory(database)
add_subdirectory(ui/profile-window)
add_subdirectory(ui/main-window)
add_subdirectory(ui/authorization-windows)
add_subdirectory(ui/note-widget)
add_subdirectory(ui/style-manager)
add_subdirectory(ui/settings-window)
add_subdirectory(ui/analytics-window)
add_subdirectory(ui/language-manager)
add_subdirectory(proto)
add_executable(EfficioTaskTracker main.cpp)

Expand All @@ -28,7 +33,12 @@ target_link_libraries(EfficioTaskTracker PRIVATE
efficio-rpc
Database
Scripts
StyleManager
LanguageManager
AuthorizationWindows
ProfileWindow
MainWindow
NoteWidget
)
SettingsWindow
AnalyticsWindow
)
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ git clone git@github.com:toximu/efficio-task-tracker.git
sudo service postgresql start && sudo -u postgres psql
```

> If you use fish shell, replace `service` with `systemctl`

3. Create **efficio** user

```SQL
Expand All @@ -39,15 +41,7 @@ GRANT ALL PRIVILEGES ON DATABASE efficio TO efficio;
\q
```

4. Enter under **efficio** profile

```bash
psql -U efficio -d efficio -h localhost
```

> After that run the server on address **localhost** and **port** 5432 in your pgAdmin4

5. Build and start app
4. Build and start app

```bash
mkdir -p build && cd build
Expand All @@ -56,6 +50,11 @@ make
./EfficioTaskTracker -platform xcb
```

## Current result

<img src="https://github.com/user-attachments/assets/d96f5bbd-fe0d-4c7f-b438-cd2de27ec1b6" width="60%"/>


## Technologies Used
- Qt 6.8.2
- PostgreSQL 17.4
Expand All @@ -64,4 +63,4 @@ make

## License

This project is licensed under the **MIT License**. See the [LICENSE](https://github.com/toximu/efficio-task-tracker/blob/main/LICENSE) file for details.
This project is licensed under the **MIT License**. See the [LICENSE](https://github.com/toximu/efficio-task-tracker/blob/main/LICENSE) file for details.
1 change: 1 addition & 0 deletions database/include/lr_dao.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class LRDao {
public:
LRDao() = default;
static int try_register_user(const QString &login, const QString &password);
static bool try_delete_user(const QString &login);
static bool validate_user(const QString &login, const QString &password);
static bool add_project_to_user(std::string user_login, int project_id);
static bool
Expand Down
2 changes: 2 additions & 0 deletions database/src/database_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ DatabaseManager::DatabaseManager() {
database_.open();

QSqlQuery query(database_);

query.exec(
"CREATE TABLE IF NOT EXISTS notes ("
"id SERIAL PRIMARY KEY, "
"title TEXT NOT NULL, "
"type TEXT NOT NULL, "
"content TEXT, "
"members VARCHAR(50)[], "
"date VARCHAR(50), "
Expand Down
9 changes: 9 additions & 0 deletions database/src/lr_dao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ int LRDao::try_register_user(const QString &login, const QString &password) {
);
}

bool LRDao::try_delete_user(const QString &login) {
QSqlQuery query;

return DatabaseManager::get_instance().execute_query(
query, "DELETE FROM users WHERE login = ?",
{login}
);
}

bool LRDao::validate_user(const QString &login, const QString &password) {
QSqlQuery query;

Expand Down
18 changes: 11 additions & 7 deletions database/src/note_dao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ bool NoteDao::initialize_note(int &id) {
QSqlQuery query;
const auto is_successful = DatabaseManager::get_instance().execute_query(
query,
"INSERT INTO notes (title, content) "
"VALUES ('Пустая заметка', '')"
"INSERT INTO notes (title, type, content) "
"VALUES ('Пустая заметка', 'actual', '')"
"RETURNING id"
);
if (is_successful && query.next()) {
Expand All @@ -23,6 +23,7 @@ bool NoteDao::update_note(const Note &note) {
const QString sql_query =
"UPDATE notes SET "
"title = :title, "
"type = :type, "
"content = :content, "
"members = :members, "
"date = :date, "
Expand All @@ -31,6 +32,7 @@ bool NoteDao::update_note(const Note &note) {
const QVariantList params = {
QString::fromStdString(note.get_title()),
QString::fromStdString(note.get_text()),
QString::fromStdString(note.get_type()),
convert_string_set_to_postgres_array(note.get_members()),
QString::fromStdString(note.get_date()),
convert_tags_to_postgres_array(note.get_tags()),
Expand Down Expand Up @@ -58,6 +60,7 @@ std::vector<Note> NoteDao::get_all_notes() {
while (query.next()) {
auto id = query.value("id").toUInt();
auto title = query.value("title").toString().toStdString();
auto type = query.value("type").toString().toStdString();
auto text = query.value("content").toString().toStdString();
notes.emplace_back(id, title, text);
}
Expand All @@ -68,22 +71,23 @@ std::vector<Note> NoteDao::get_all_notes() {
Note NoteDao::get_note_by_id(int id) {
QSqlQuery query;
DatabaseManager::get_instance().execute_query(
query, "SELECT title, content, array_to_string(tags, ','), date, array_to_string(members, ',') FROM notes WHERE id = ?", {id}
query, "SELECT title, type, content, array_to_string(tags, ','), date, array_to_string(members, ',') FROM notes WHERE id = ?", {id}
);
query.next();
auto title = query.value(0).toString().toStdString();
auto text = query.value(1).toString().toStdString();
auto date = query.value(3).toString().toStdString();
auto type = query.value(1).toString().toStdString();
auto text = query.value(2).toString().toStdString();
auto date = query.value(4).toString().toStdString();
Note result{id, title, text};
auto tags_list = query.value(2).toString().split(",");
auto tags_list = query.value(3).toString().split(",");

if (!tags_list.empty() && tags_list[0] != "") {
for (const auto& tag_str : tags_list) {

result.add_tag(tag_str.split(':')[0].toStdString(), tag_str.split(':')[1].toStdString());
}
}
auto member_list = query.value(4).toString().split(",");
auto member_list = query.value(5).toString().split(",");
if (!member_list.empty() && member_list[0] != "") {
for (const auto& member : member_list) {
result.add_member(member.toStdString());
Expand Down
50 changes: 50 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <QApplication>
#include <QLocale>
#include <QScreen>
#include <QTranslator>
#include <QSettings>
#include "applicationwindow.h"
#include "login_window.h"
#include "style_manager.h"
#include "language_manager.h"
#include <QLibraryInfo>

int main(int argc, char *argv[]) {
QApplication app(argc, argv);

app.setApplicationName("EFFICIO");
app.setApplicationDisplayName("EFFICIO");
app.setOrganizationName("EFFICIO");
app.setWindowIcon(QIcon(":/icons/app_icon.png"));

QTranslator appTranslator;
QTranslator qtTranslator;

QSettings settings;
QString language = settings.value("Language", QLocale::system().name()).toString();

if (appTranslator.load(":/translations/app_" + language + ".qm")) {
app.installTranslator(&appTranslator);
}

if (qtTranslator.load("qt_" + language, QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
app.installTranslator(&qtTranslator);
}

StyleManager* style_manager = StyleManager::instance();
LanguageManager* language_manager = LanguageManager::instance();

QMainWindow *app_window = new QMainWindow();
app_window->setWindowTitle("EFFICIO");
auto *login_window = new LoginWindow(app_window);

app_window->setCentralWidget(login_window);
const QRect screen_geometry = QApplication::primaryScreen()->availableGeometry();
const int x = (screen_geometry.width() - login_window->width()) / 2;
const int y = (screen_geometry.height() - login_window->height()) / 2;
app_window->move(x, y);
app_window->show();

return app.exec();

}
3 changes: 3 additions & 0 deletions scripts/include/note.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ class Note {
[[nodiscard]] const std::string &get_title() const;
[[nodiscard]] const std::string &get_text() const;
[[nodiscard]] const std::string &get_date() const;
[[nodiscard]] const std::string &get_type() const;
[[nodiscard]] const std::vector<Tag> &get_tags() const;
[[nodiscard]] const std::unordered_set<std::string> &get_members() const;

void set_title(const std::string &title);
void set_text(const std::string &text);
void set_type(const std::string &type);
void add_tag(const std::string &tag, const std::string &color = "#e7624b");
void set_date(const std::string &date);
void add_member(const std::string &member);
Expand All @@ -37,6 +39,7 @@ class Note {
std::string title_;
std::string text_;
std::string date_;
std::string type_;
std::vector<Tag> tags_;
std::unordered_set<std::string> members_;
};
Expand Down
8 changes: 8 additions & 0 deletions scripts/src/note.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Note::Note(const int id, std::string title, std::string text)
return text_;
}

[[nodiscard]] const std::string &Note::get_type() const {
return type_;
}

const std::string &Note::get_date() const {
return date_;
}
Expand All @@ -40,6 +44,10 @@ void Note::set_text(const std::string &text) {
text_ = text;
}

void Note::set_type(const std::string &type) {
type_ = type;
}

void Note::add_tag(const std::string &tag, const std::string &color) {
tags_.push_back({tag, color});
}
Expand Down
42 changes: 42 additions & 0 deletions ui/analytics-window/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
cmake_minimum_required(VERSION 3.16)

project(AnalyticsWindow LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 COMPONENTS Widgets Core Gui Sql Charts REQUIRED)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

set(SOURCES
src/analytics_window.cpp
)

set(HEADERS
include/analytics_window.h
include/analytics_window_style_sheet.h
)

add_library(AnalyticsWindow STATIC ${SOURCES} ${HEADERS})

target_include_directories(AnalyticsWindow
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

target_link_libraries(AnalyticsWindow
PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Sql
Database
StyleManager
LanguageManager
PUBLIC
Qt6::Widgets
Qt6::Charts
)
45 changes: 45 additions & 0 deletions ui/analytics-window/include/analytics_window.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef ANALYTICS_DIALOG_H
#define ANALYTICS_DIALOG_H

#include <QDialog>
#include <QtCharts>
#include <QChartView>
#include <QPieSeries>
#include <vector>

class AnalyticsWindow : public QDialog
{
Q_OBJECT

public:
explicit AnalyticsWindow(
QWidget *parent = nullptr,
int created_count = 3,
int completed_count = 4,
int expired_count = 5
);
~AnalyticsWindow();

static const std::vector<QString> THEMES;

private:

void handle_theme_changed(int theme);
void handle_font_size_changed(std::string font_size);
void handle_language_changed(std::string new_language);
void on_switch_theme_clicked();
void setup_chart();

int m_created_count;
int m_completed_count;
int m_expired_count;

QChartView *chart_view;
QPieSeries *series;
QChart *chart;
QPieSlice *completed_slice;
QPieSlice *expired_slice;
QPieSlice *created_slice;
};

#endif // ANALYTICS_DIALOG_H
Loading