diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..99ce9f1 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,34 @@ +name: Build Project + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: '6.5.*' + host: 'linux' + target: 'desktop' + modules: 'qtcore qtwidgets' + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release + + - name: Build + run: cmake --build ${{github.workspace}}/build --config Release + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: MyCppPlanner + path: ${{github.workspace}}/build/MyCppPlanner diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c94ba1..9f027eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,30 +7,44 @@ endif() project ("MyCppPlanner") -set(CMAKE_PREFIX_PATH "C:/Program Files/6.5.2/msvc2019_64") +set(CMAKE_PREFIX_PATH "C:\\Cpp\\6.8.2\\mingw_64") find_package(Qt6 REQUIRED COMPONENTS Core Widgets) - -# Добавляем поддержку UI файлов + set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) add_executable (MyCppPlanner - "src/main.cpp" - - - "include/main_window.h" - "src/main_window.cpp" - "include/register_window.h") - -# Добавляем линковку с Qt + "main.cpp" + + "include/managers/app_state_manager.h" + "include/managers/notification_manager.h" + "include/managers/password_manager.h" + "include/managers/settings_manager.h" + "include/managers/tasks_manager.h" + "include/managers/window_manager.h" + + + + + "src/managers/app_state_manager.cpp" + "src/managers/notification_manager.cpp" + "src/managers/password_manager.cpp" + "src/managers/settings_manager.cpp" + "src/managers/tasks_manager.cpp" + "src/managers/window_manager.cpp" + + + + "include/windows/register_window.h" "src/windows/register_window.cpp" "src/windows/main_window.cpp" "src/windows/settings_window.cpp") + +#Qt lib target_link_libraries(MyCppPlanner PRIVATE Qt6::Core Qt6::Widgets ) -# Добавляем пути к заголовочным файлам target_include_directories(MyCppPlanner PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ) diff --git a/include/main_window.h b/include/main_window.h deleted file mode 100644 index c772906..0000000 --- a/include/main_window.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - MainWindow(QWidget* parent = nullptr); - ~MainWindow(); - -private: - void setupUI(); -}; diff --git a/include/managers/app_state_manager.h b/include/managers/app_state_manager.h new file mode 100644 index 0000000..a5593a3 --- /dev/null +++ b/include/managers/app_state_manager.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +class StateManager { +public: + static StateManager& instance(); + + enum class AppState { + Unauthorized, + Authorized, + Loading, + Error, + Banned + }; + + void setAppState(AppState state); + AppState getCurrentState() const; + + void setError(const QString& error); + QString getLastError() const; + void clearErrors(); + + bool isAuthorized() const; + void setAuthorized(bool auth); + +private: + static const QString SETTINGS_ORG; + static const QString SETTINGS_APP; + static const QString KEY_APP_STATE; + + StateManager() = default; + ~StateManager() = default; + + void saveState(); + void loadState(); + + AppState currentState; + QList lastError; + + StateManager(const StateManager&) = delete; + StateManager& operator=(const StateManager&) = delete; +}; \ No newline at end of file diff --git a/include/managers/notification_manager.h b/include/managers/notification_manager.h new file mode 100644 index 0000000..e4f4865 --- /dev/null +++ b/include/managers/notification_manager.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include + +struct Notification { + QString id; + QString taskId; + QDateTime time; + bool isRead; + QString message; +}; + +class NotificationManager { +public: + static NotificationManager& instance(); + + void addNotification(const QString& taskId, const QDateTime& time, const QString& message); + void markAsRead(const QString& notificationId); + void deleteNotification(const QString& notificationId); + + QList getPendingNotifications() const; + QList getNotificationsForTask(const QString& taskId) const; + bool numberOfUnreadNotifications() const; + + void clearOldNotifications(const QDateTime& before); + void clearAllNotifications(); + +private: + static const QString SETTINGS_ORG; + static const QString SETTINGS_APP; + static const QString KEY_NOTIFICATIONS; + static const QString KEY_LAST_CHECK; + + NotificationManager() = default; + ~NotificationManager() = default; + + void deleteAllData(); + QString generateNotificationId() const; + void saveNotifications() const; + void loadNotifications(); + + QList notifications; + + NotificationManager(const NotificationManager&) = delete; + NotificationManager& operator=(const NotificationManager&) = delete; +}; \ No newline at end of file diff --git a/include/managers/password_manager.h b/include/managers/password_manager.h new file mode 100644 index 0000000..91e755a --- /dev/null +++ b/include/managers/password_manager.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include +#include + +class PasswordManager { +public: + static PasswordManager& instance(); + + void saveUserInfo(const QString& username, const QString& password, bool rememberMe); + void deleteUserInfo(const QString& username, const QString& password); + + bool hasStoredInfo() const; + + QString getStoredUsername() const; //Don't forget to check via hasStoredInfo()!!! + QString getStoredPassword() const; + + bool checkPassword(const QString& inputPassword, const QString& storedPassword); + +private: + //Encrypting settings + static constexpr int SALT_LENGTH = 16; + static const QString HASH_SEPARATOR; + + // Setting keys + static const QString SETTINGS_ORG; + static const QString SETTINGS_APP; + static const QString KEY_USERNAME; + static const QString KEY_PASSWORD; + static const QString KEY_REMEMBER_ME; + + PasswordManager() = default; + ~PasswordManager() = default; + + void deleteAllData(); + QString generateSalt(int length); + QString hashPassword(const QString& password, const QString& salt); + QString encryptPassword(const QString& password); + + + PasswordManager(const PasswordManager&) = delete; + PasswordManager& operator=(const PasswordManager&) = delete; //Singleton pattern +}; \ No newline at end of file diff --git a/include/managers/settings_manager.h b/include/managers/settings_manager.h new file mode 100644 index 0000000..6a91d30 --- /dev/null +++ b/include/managers/settings_manager.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +class SettingsManager { +public: + static SettingsManager& instance(); + + QString getLanguage() const; + void setLanguage(const QString& lang); + QString getTheme() const; + void setTheme(const QString& theme); + + bool areNotificationsEnabled() const; + void setNotificationsEnabled(bool enabled); + int getNotificationLeadTime() const; + void setNotificationLeadTime(int minutes); + +private: + static const QString SETTINGS_ORG; + static const QString SETTINGS_APP; + static const QString KEY_LANGUAGE; + static const QString KEY_THEME; + static const QString KEY_NOTIFICATIONS_ENABLED; + static const QString KEY_NOTIFICATION_LEAD_TIME; + + SettingsManager() = default; + ~SettingsManager() = default; + + void deleteAllData(); + void loadDefaults(); + + SettingsManager(const SettingsManager&) = delete; + SettingsManager& operator=(const SettingsManager&) = delete; +}; \ No newline at end of file diff --git a/include/managers/tasks_manager.h b/include/managers/tasks_manager.h new file mode 100644 index 0000000..052fb70 --- /dev/null +++ b/include/managers/tasks_manager.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include + +class Task { +public: + enum class Priority { Low, Medium, High, Incredible }; + enum class Status { ToDo, InProgress, Done }; + + QString id; + QString title; + QString description; + QDateTime startTime; + QDateTime deadline; + Priority priority; + Status status; + QString category; + + bool hasNotification; +}; + +class TasksManager { +public: + static TasksManager& instance(); + + QString addTask(const Task& task); + bool updateTask(const QString& taskId, const Task& task); + bool deleteTask(const QString& taskId); + Task getTask(const QString& taskId) const; + + QList getAllTasks() const; + QList getTasksByStatus(Task::Status status) const; + QList getTasksBeforeDeadline(const QDate& date) const; + QList getTasksAfterDeadline(const QDate& date) const; + + QStringList getCategories() const; + void addCategory(const QString& category); + void removeCategory(const QString& category); + +private: + static const QString SETTINGS_ORG; + static const QString SETTINGS_APP; + static const QString KEY_TASKS; + static const QString KEY_CATEGORIES; + + TasksManager() = default; + ~TasksManager() = default; + + QList getTasksByDeadline(const QDate& date, std::function cond) const; + + void deleteAllData(); + QString generateTaskId() const; + void saveTasks() const; + void loadTasks(); + + QList tasks; + QStringList categories; + + TasksManager(const TasksManager&) = delete; + TasksManager& operator=(const TasksManager&) = delete; +}; \ No newline at end of file diff --git a/include/managers/window_manager.h b/include/managers/window_manager.h new file mode 100644 index 0000000..cfb8863 --- /dev/null +++ b/include/managers/window_manager.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include "../windows/base_window.h" + +using WindowParams = std::variant; +using WindowParamsMap = std::unordered_map; + +class WindowManager { +public: + static WindowManager& instance(); + + void showWindow(WindowType type, const WindowParamsMap& params = {}); + + void closeCurrentWindow(); + + void closeAllAndShow(WindowType type, const WindowParamsMap& params = {}); + + void hideCurrentWindow(); + + BaseWindow* getCurrentWindow() const; + + WindowType getLastWindow() const; + + QStack navigationHistory; + +private: + static const QString SETTINGS_ORG; + static const QString SETTINGS_APP; + static const QString KEY_LAST_WINDOW; + + WindowManager() = default; + ~WindowManager(); + + void saveLastWindow(WindowType type); + + std::unique_ptr createWindow(WindowType type, const WindowParamsMap& params); + + QStack> windows; + + WindowManager(const WindowManager&) = delete; + WindowManager& operator=(const WindowManager&) = delete; +}; \ No newline at end of file diff --git a/include/register_window.h b/include/register_window.h deleted file mode 100644 index 2928e88..0000000 --- a/include/register_window.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - -private: - void setupUI(); -}; \ No newline at end of file diff --git a/include/windows/base_window.h b/include/windows/base_window.h new file mode 100644 index 0000000..0ca50d2 --- /dev/null +++ b/include/windows/base_window.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +enum class WindowType { + Login, + Main, + Settings, + TaskDetails, + Calendar +}; + +class BaseWindow : public QWidget { + Q_OBJECT + +public: + explicit BaseWindow(WindowType type, QWidget* parent = nullptr) + : QWidget(parent), type(type) { + } + + virtual ~BaseWindow() = default; + WindowType type; + virtual void show() = 0; + + + +protected: + virtual void setupUI() = 0; + virtual void cleanup() {} + + virtual void showNextWindow(WindowType type) { Q_UNUSED(type); } + virtual void goBack() {} + virtual void goHome() {} +}; \ No newline at end of file diff --git a/include/windows/main_window.h b/include/windows/main_window.h new file mode 100644 index 0000000..e69de29 diff --git a/include/windows/register_window.h b/include/windows/register_window.h new file mode 100644 index 0000000..74d2100 --- /dev/null +++ b/include/windows/register_window.h @@ -0,0 +1,23 @@ +#pragma once +#include "base_window.h" +#include + +class RegisterWindow : public BaseWindow { + Q_OBJECT + +public: + RegisterWindow(QWidget* parent = nullptr); + void initialize() override; + +private: + void setupUI(); + void createConnections(); + +private slots: + void onRegisterClicked(); + +private: + QLineEdit* usernameInput; + QLineEdit* passwordInput; + QPushButton* registerButton; +}; \ No newline at end of file diff --git a/include/windows/settings_window.h b/include/windows/settings_window.h new file mode 100644 index 0000000..e69de29 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..3c9db93 --- /dev/null +++ b/main.cpp @@ -0,0 +1,5 @@ +#include + +int main(int argc, char *argv[]) { + return 0; +} diff --git a/src/images/all_bars.jpg b/src/images/all_bars.jpg new file mode 100644 index 0000000..3826f25 Binary files /dev/null and b/src/images/all_bars.jpg differ diff --git a/src/images/blue_bar.png b/src/images/blue_bar.png new file mode 100644 index 0000000..f16ac2b Binary files /dev/null and b/src/images/blue_bar.png differ diff --git a/src/images/go_back.png b/src/images/go_back.png new file mode 100644 index 0000000..91843a5 Binary files /dev/null and b/src/images/go_back.png differ diff --git a/src/images/go_home.png b/src/images/go_home.png new file mode 100644 index 0000000..95eae8b Binary files /dev/null and b/src/images/go_home.png differ diff --git a/src/images/goluboi_bar.png b/src/images/goluboi_bar.png new file mode 100644 index 0000000..4bc3942 Binary files /dev/null and b/src/images/goluboi_bar.png differ diff --git a/src/images/gradient_bar.png b/src/images/gradient_bar.png new file mode 100644 index 0000000..6ab1224 Binary files /dev/null and b/src/images/gradient_bar.png differ diff --git a/src/images/green_bar.png b/src/images/green_bar.png new file mode 100644 index 0000000..53d5f39 Binary files /dev/null and b/src/images/green_bar.png differ diff --git a/src/images/input_field.png b/src/images/input_field.png new file mode 100644 index 0000000..8f823d3 Binary files /dev/null and b/src/images/input_field.png differ diff --git a/src/images/light_purple_bar.png b/src/images/light_purple_bar.png new file mode 100644 index 0000000..734963c Binary files /dev/null and b/src/images/light_purple_bar.png differ diff --git a/src/images/purple_bar.png b/src/images/purple_bar.png new file mode 100644 index 0000000..cd17fdb Binary files /dev/null and b/src/images/purple_bar.png differ diff --git a/src/images/registration_bg.gif b/src/images/registration_bg.gif new file mode 100644 index 0000000..9427cc8 Binary files /dev/null and b/src/images/registration_bg.gif differ diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index b78bce7..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "../include//mainwindow.h" -#include - -int main(int argc, char *argv[]) { - QApplication app(argc, argv); - MainWindow window; - window.show(); - - return app.exec(); -} diff --git a/src/main_window.cpp b/src/main_window.cpp deleted file mode 100644 index 059905b..0000000 --- a/src/main_window.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "../include/mainwindow.h" -#include -#include - -MainWindow::MainWindow(QWidget* parent) - : QMainWindow(parent) -{ - setupUI(); -} - -MainWindow::~MainWindow() -{ -} - -void MainWindow::setupUI() -{ - QWidget* centralWidget = new QWidget(this); - setCentralWidget(centralWidget); - - QVBoxLayout* layout = new QVBoxLayout(centralWidget); - QCalendarWidget* calendar = new QCalendarWidget(this); - layout->addWidget(calendar); - - resize(800, 600); - setWindowTitle("My Calendar Application"); -} \ No newline at end of file diff --git a/src/managers/app_state_manager.cpp b/src/managers/app_state_manager.cpp new file mode 100644 index 0000000..9a82053 --- /dev/null +++ b/src/managers/app_state_manager.cpp @@ -0,0 +1,55 @@ +#include "../../include/managers/app_state_manager.h" +#include + +const QString StateManager::SETTINGS_ORG = "AppState"; +const QString StateManager::SETTINGS_APP = "MyCppPlanner"; +const QString StateManager::KEY_APP_STATE = "app_state"; + +StateManager& StateManager::instance() { + static StateManager instance; + return instance; +} + +void StateManager::setAppState(AppState state) { + currentState = state; + saveState(); +} + +StateManager::AppState StateManager::getCurrentState() const { + return currentState; +} + +void StateManager::setError(const QString& error) { + lastError.append(error); + if (lastError.size() > 10) { // Only 10 errors saved + lastError.removeFirst(); + } + setAppState(AppState::Error); +} + +QString StateManager::getLastError() const { + return lastError.isEmpty() ? QString() : lastError.last(); +} + +void StateManager::clearErrors() { + lastError.clear(); +} + +bool StateManager::isAuthorized() const { + return currentState == AppState::Authorized; +} + +void StateManager::setAuthorized(bool auth) { + setAppState(auth ? AppState::Authorized : AppState::Unauthorized); +} + +void StateManager::saveState() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_APP_STATE, static_cast(currentState)); +} + +void StateManager::loadState() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + currentState = static_cast(settings.value(KEY_APP_STATE, + static_cast(AppState::Unauthorized)).toInt()); +} \ No newline at end of file diff --git a/src/managers/notification_manager.cpp b/src/managers/notification_manager.cpp new file mode 100644 index 0000000..3141602 --- /dev/null +++ b/src/managers/notification_manager.cpp @@ -0,0 +1,143 @@ +#include "../../include/managers/notification_manager.h" +#include +#include +#include +#include + +const QString NotificationManager::SETTINGS_ORG = "Notifications"; +const QString NotificationManager::SETTINGS_APP = "MyCppPlanner"; +const QString NotificationManager::KEY_NOTIFICATIONS = "notifications"; +const QString NotificationManager::KEY_LAST_CHECK = "last_notification_check"; + +NotificationManager& NotificationManager::instance() { + static NotificationManager instance; + return instance; +} + +void NotificationManager::addNotification(const QString& taskId, const QDateTime& time, const QString& message) { + Notification notification; + notification.id = generateNotificationId(); + notification.taskId = taskId; + notification.time = time; + notification.isRead = false; + notification.message = message; + + notifications.append(notification); + saveNotifications(); +} + +void NotificationManager::markAsRead(const QString& notificationId) { + for (auto& notification : notifications) { + if (notification.id == notificationId) { + notification.isRead = true; + break; + } + } + saveNotifications(); +} + +void NotificationManager::deleteNotification(const QString& notificationId) { + for (int i = 0; i < notifications.size(); ++i) { + if (notifications[i].id == notificationId) { + notifications.removeAt(i); + break; + } + } + saveNotifications(); +} + +QList NotificationManager::getPendingNotifications() const { + QList pending; + QDateTime now = QDateTime::currentDateTime(); + + for (const auto& notification : notifications) { + if (!notification.isRead && notification.time <= now) { + pending.append(notification); + } + } + return pending; +} + +QList NotificationManager::getNotificationsForTask(const QString& taskId) const { + QList taskNotifications; + for (const auto& notification : notifications) { + if (notification.taskId == taskId) { + taskNotifications.append(notification); + } + } + return taskNotifications; +} + +bool NotificationManager::numberOfUnreadNotifications() const { + int count = 0; + for (const auto& notification : notifications) { + if (!notification.isRead) { + count++; + } + } + return count > 0; +} + +void NotificationManager::clearOldNotifications(const QDateTime& before) { + notifications.erase( + std::remove_if(notifications.begin(), notifications.end(), + [&before](const Notification& n) { return n.time < before; }), + notifications.end()); + saveNotifications(); +} + +void NotificationManager::clearAllNotifications() { + notifications.clear(); + saveNotifications(); +} + +void NotificationManager::deleteAllData() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.remove(KEY_NOTIFICATIONS); + settings.remove(KEY_LAST_CHECK); + notifications.clear(); +} + +QString NotificationManager::generateNotificationId() const { + return QUuid::createUuid().toString(QUuid::WithoutBraces); +} + +void NotificationManager::saveNotifications() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + QJsonArray notificationsArray; + + for (const auto& notification : notifications) { + QJsonObject notificationObj; + notificationObj["id"] = notification.id; + notificationObj["taskId"] = notification.taskId; + notificationObj["time"] = notification.time.toString(Qt::ISODate); + notificationObj["isRead"] = notification.isRead; + notificationObj["message"] = notification.message; + notificationsArray.append(notificationObj); + } + + settings.setValue(KEY_NOTIFICATIONS, QJsonDocument(notificationsArray).toJson(QJsonDocument::Compact)); +} + +void NotificationManager::loadNotifications() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + notifications.clear(); + + QByteArray data = settings.value(KEY_NOTIFICATIONS).toByteArray(); + if (!data.isEmpty()) { + QJsonDocument doc = QJsonDocument::fromJson(data); + if (doc.isArray()) { + QJsonArray notificationsArray = doc.array(); + for (const auto& notificationValue : notificationsArray) { + QJsonObject notificationObj = notificationValue.toObject(); + Notification notification; + notification.id = notificationObj["id"].toString(); + notification.taskId = notificationObj["taskId"].toString(); + notification.time = QDateTime::fromString(notificationObj["time"].toString(), Qt::ISODate); + notification.isRead = notificationObj["isRead"].toBool(); + notification.message = notificationObj["message"].toString(); + notifications.append(notification); + } + } + } +} \ No newline at end of file diff --git a/src/managers/password_manager.cpp b/src/managers/password_manager.cpp new file mode 100644 index 0000000..4523991 --- /dev/null +++ b/src/managers/password_manager.cpp @@ -0,0 +1,98 @@ +#include "../include/managers/password_manager.h" +#include +#include +#include +#include +#include + +const QString PasswordManager::HASH_SEPARATOR = ":"; +const QString PasswordManager::SETTINGS_ORG = "LoginData"; +const QString PasswordManager::SETTINGS_APP = "MyCppPlanner"; +const QString PasswordManager::KEY_USERNAME = "username"; +const QString PasswordManager::KEY_PASSWORD = "password"; +const QString PasswordManager::KEY_REMEMBER_ME = "remember_me"; + + +// Private help methods + +QString PasswordManager::generateSalt(int length) { + QByteArray salt(length, 0); + QRandomGenerator* generator = QRandomGenerator::global(); + for (int i = 0; i < length; ++i) { + salt[i] = static_cast(generator->generate() & 0xFF); + } + + return QString(salt.toHex()); +} + +QString PasswordManager::hashPassword(const QString& password, const QString& salt) { + QByteArray hashedPassword = QCryptographicHash::hash(password.toUtf8() + salt.toUtf8(), QCryptographicHash::Sha256); + return QString(hashedPassword.toHex()); +} + +QString PasswordManager::encryptPassword(const QString& password) { + QString salt = generateSalt(SALT_LENGTH); + QString hashedPassword = hashPassword(password, salt); + return salt + HASH_SEPARATOR + hashedPassword; +} + +// End private help methods here <0_-> + +PasswordManager& PasswordManager::instance() { + static PasswordManager instance; + return instance; +} + +void PasswordManager::deleteAllData() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.clear(); +} + +void PasswordManager::saveUserInfo(const QString& username, const QString& password, bool rememberMe) { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + if (rememberMe) { + settings.setValue(KEY_USERNAME, username); + + settings.setValue(KEY_PASSWORD, encryptPassword(password)); + settings.setValue(KEY_REMEMBER_ME, true); + } + else { + deleteUserInfo(username, password); + } +} + +bool PasswordManager::checkPassword(const QString& inputPassword, const QString& storedPassword) { + QStringList parts = storedPassword.split(":"); + if (parts.size() != 2) { + return false; + } + + QString salt = parts[0]; + QString storedHashedPassword = parts[1]; + + QString hashedInputPassword = hashPassword(inputPassword, salt); + return hashedInputPassword == storedHashedPassword; +} + +void PasswordManager::deleteUserInfo(const QString& username, const QString& password) { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + + settings.remove(KEY_USERNAME); + settings.remove(KEY_PASSWORD); + settings.remove(KEY_REMEMBER_ME); +} + +bool PasswordManager::hasStoredInfo() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return settings.value(KEY_REMEMBER_ME, false).toBool(); +} + +QString PasswordManager::getStoredUsername() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return settings.value(KEY_USERNAME).toString(); +} + +QString PasswordManager::getStoredPassword() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return settings.value(KEY_PASSWORD).toString(); +} \ No newline at end of file diff --git a/src/managers/settings_manager.cpp b/src/managers/settings_manager.cpp new file mode 100644 index 0000000..49aa917 --- /dev/null +++ b/src/managers/settings_manager.cpp @@ -0,0 +1,66 @@ +#include "../../include/managers/settings_manager.h" + +const QString SettingsManager::SETTINGS_ORG = "Settings"; +const QString SettingsManager::SETTINGS_APP = "MyCppPlanner"; +const QString SettingsManager::KEY_LANGUAGE = "language"; +const QString SettingsManager::KEY_THEME = "theme"; +const QString SettingsManager::KEY_NOTIFICATIONS_ENABLED = "notifications_enabled"; +const QString SettingsManager::KEY_NOTIFICATION_LEAD_TIME = "notification_lead_time"; + +SettingsManager& SettingsManager::instance() { + static SettingsManager instance; + return instance; +} + +QString SettingsManager::getLanguage() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return settings.value(KEY_LANGUAGE, "en").toString(); +} + +void SettingsManager::setLanguage(const QString& lang = "en") { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_LANGUAGE, lang); +} + +QString SettingsManager::getTheme() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return settings.value(KEY_THEME, "dark").toString(); // Dark theme start +} + +void SettingsManager::setTheme(const QString& theme = "dark") { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_THEME, theme); +} + +bool SettingsManager::areNotificationsEnabled() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return settings.value(KEY_NOTIFICATIONS_ENABLED, true).toBool(); +} + +void SettingsManager::setNotificationsEnabled(bool enabled = true) { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_NOTIFICATIONS_ENABLED, enabled); +} + +int SettingsManager::getNotificationLeadTime() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return settings.value(KEY_NOTIFICATION_LEAD_TIME, 15).toInt(); +} + +void SettingsManager::setNotificationLeadTime(int minutes = 15) { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_NOTIFICATION_LEAD_TIME, minutes); +} + +void SettingsManager::deleteAllData() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.clear(); + loadDefaults(); +} + +void SettingsManager::loadDefaults() { + setLanguage(); + setTheme(); + setNotificationsEnabled(); + setNotificationLeadTime(); +} \ No newline at end of file diff --git a/src/managers/tasks_manager.cpp b/src/managers/tasks_manager.cpp new file mode 100644 index 0000000..d89092c --- /dev/null +++ b/src/managers/tasks_manager.cpp @@ -0,0 +1,173 @@ +#include "../../include/managers/tasks_manager.h" +#include +#include +#include +#include +#include +#include + +const QString TasksManager::SETTINGS_ORG = "Tasks"; +const QString TasksManager::SETTINGS_APP = "MyCppPlanner"; +const QString TasksManager::KEY_TASKS = "tasks"; +const QString TasksManager::KEY_CATEGORIES = "categories"; + +TasksManager& TasksManager::instance() { + static TasksManager instance; + return instance; +} + +QString TasksManager::addTask(const Task& task) { + Task newTask = task; + newTask.id = generateTaskId(); + tasks.append(newTask); + saveTasks(); + return newTask.id; +} + +bool TasksManager::updateTask(const QString& taskId, const Task& task) { + for (int i = 0; i < tasks.size(); ++i) { + if (tasks[i].id == taskId) { + Task updatedTask = task; + updatedTask.id = taskId; + tasks[i] = updatedTask; + saveTasks(); + return true; + } + } + return false; +} + +bool TasksManager::deleteTask(const QString& taskId) { + for (int i = 0; i < tasks.size(); ++i) { + if (tasks[i].id == taskId) { + tasks.removeAt(i); + saveTasks(); + return true; + } + } + return false; +} + +Task TasksManager::getTask(const QString& taskId) const { + for (const auto& task : tasks) { + if (task.id == taskId) { + return task; + } + } + return Task(); +} + +QList TasksManager::getAllTasks() const { + return tasks; +} + +QList TasksManager::getTasksByStatus(Task::Status status) const { + QList filteredTasks; + for (const auto& task : tasks) { + if (task.status == status) { + filteredTasks.append(task); + } + } + return filteredTasks; +} + +QList TasksManager::getTasksByDeadline(const QDate& date, std::function cond) const { + QList filteredTasks; + for (const auto& task : tasks) { + if (cond(task.deadline.date(), date)) { + filteredTasks.append(task); + } + } + return filteredTasks; +} + +QList TasksManager::getTasksBeforeDeadline(const QDate& date) const { + auto lessThanOrEqualTo = [](const QDate& a, const QDate& b) { return a <= b; }; + return getTasksByDeadline(date, lessThanOrEqualTo); +} + +QList TasksManager::getTasksAfterDeadline(const QDate& date) const { + auto biggerThanOrEqualTo = [](const QDate& a, const QDate& b) { return a >= b; }; + return getTasksByDeadline(date, biggerThanOrEqualTo); +} + +QStringList TasksManager::getCategories() const { + return categories; +} + +void TasksManager::addCategory(const QString& category) { + if (!categories.contains(category)) { + categories.append(category); + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_CATEGORIES, categories); + } +} + +void TasksManager::removeCategory(const QString& category) { + if (categories.removeOne(category)) { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_CATEGORIES, categories); + } +} + +void TasksManager::deleteAllData() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.remove(KEY_TASKS); + settings.remove(KEY_CATEGORIES); + tasks.clear(); + categories.clear(); +} + +QString TasksManager::generateTaskId() const { + return QUuid::createUuid().toString(QUuid::WithoutBraces); +} + +void TasksManager::saveTasks() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + QJsonArray tasksArray; + + for (const auto& task : tasks) { + QJsonObject taskObj; + taskObj["id"] = task.id; + taskObj["title"] = task.title; + taskObj["description"] = task.description; + taskObj["startTime"] = task.startTime.toString(Qt::ISODate); + taskObj["deadline"] = task.deadline.toString(Qt::ISODate); + taskObj["priority"] = static_cast(task.priority); + taskObj["status"] = static_cast(task.status); + taskObj["category"] = task.category; + taskObj["hasNotification"] = task.hasNotification; + tasksArray.append(taskObj); + } + + settings.setValue(KEY_TASKS, QJsonDocument(tasksArray).toJson(QJsonDocument::Compact)); +} + +void TasksManager::loadTasks() { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + tasks.clear(); + + QByteArray data = settings.value(KEY_TASKS).toByteArray(); + if (!data.isEmpty()) { + QJsonDocument doc = QJsonDocument::fromJson(data); + if (doc.isArray()) { + QJsonArray tasksArray = doc.array(); + for (const auto& taskValue : tasksArray) { + QJsonObject taskObj = taskValue.toObject(); + Task task; + task.id = taskObj["id"].toString(); + task.title = taskObj["title"].toString(); + task.description = taskObj["description"].toString(); + task.startTime = QDateTime::fromString(taskObj["startTime"].toString(), Qt::ISODate); + task.deadline = QDateTime::fromString(taskObj["deadline"].toString(), Qt::ISODate); + task.priority = static_cast(taskObj["priority"].toInt()); + task.status = static_cast(taskObj["status"].toInt()); + task.category = taskObj["category"].toString(); + task.hasNotification = taskObj["hasNotification"].toBool(); + tasks.append(task); + } + } + } + + categories = settings.value(KEY_CATEGORIES).toStringList(); +} \ No newline at end of file diff --git a/src/managers/window_manager.cpp b/src/managers/window_manager.cpp new file mode 100644 index 0000000..71cad81 --- /dev/null +++ b/src/managers/window_manager.cpp @@ -0,0 +1,90 @@ +#include "../../include/managers/window_manager.h" +#include "../../include/windows/main_window.h" +#include "../../include/windows/settings_window.h" +#include "../../include/windows/register_window.h" +#include + +const QString WindowManager::SETTINGS_ORG = "MyPlanner"; +const QString WindowManager::SETTINGS_APP = "PlannerApp"; +const QString WindowManager::KEY_LAST_WINDOW = "LastWindow"; + +WindowManager& WindowManager::instance() { + static WindowManager instance; + return instance; +} + +WindowManager::~WindowManager() { + while (!windows.isEmpty()) { + windows.pop(); + } +} + +void WindowManager::showWindow(WindowType type, const WindowParamsMap& params) { + auto newWindow = createWindow(type, params); + if (!newWindow) return; + + newWindow->show(); + windows.push(std::move(newWindow)); + navigationHistory.push(type); + saveLastWindow(type); +} + +void WindowManager::hideCurrentWindow() { + if (!windows.isEmpty()) { + windows.top()->hide(); + } +} + +void WindowManager::closeCurrentWindow() { + if (windows.isEmpty()) return; + + windows.pop(); + navigationHistory.pop(); + + if (!windows.isEmpty()) { + windows.top()->show(); + saveLastWindow(windows.top()->type); + } +} + +void WindowManager::closeAllAndShow(WindowType type, const WindowParamsMap& params) { + while (!windows.isEmpty()) { + windows.pop(); + } + navigationHistory.clear(); + + showWindow(type, params); +} + +BaseWindow* WindowManager::getCurrentWindow() const { + return windows.isEmpty() ? nullptr : windows.top().get(); +} + +WindowType WindowManager::getLastWindow() const { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + return static_cast(settings.value(KEY_LAST_WINDOW, static_cast(WindowType::Login)).toInt()); +} + +void WindowManager::saveLastWindow(WindowType type) { + QSettings settings(SETTINGS_ORG, SETTINGS_APP); + settings.setValue(KEY_LAST_WINDOW, static_cast(type)); +} + +std::unique_ptr WindowManager::createWindow(WindowType type, const WindowParamsMap& params) { + std::unique_ptr window; + + switch (type) { + case WindowType::Login: + window = std::make_unique(); + break; + // ToDO: Add more + default: + return nullptr; + } + + if (window) { + window->initialize(); + } + + return window; +} \ No newline at end of file diff --git a/src/windows/base_window.cpp b/src/windows/base_window.cpp new file mode 100644 index 0000000..0fe3ee5 --- /dev/null +++ b/src/windows/base_window.cpp @@ -0,0 +1,22 @@ +//Nothing to do here +//Made file just to keep structure + +/* +Once upon a time in the land of Codeville, there lived a coder named Barry, who was very proud of his C++ skills. One day, his friend Tim, a C# enthusiast, challenged him to a duel of wits to determine whose language was superior. + +Barry boasted, "C++ is like a fine wine; it gets better with age!" Tim smirked and replied, "Yeah? Well, C# is like a delightful cakeeveryone loves it!" + +To settle the argument, they decided to have a programming contest. The task? Create a program that could make coffee. Barry immediately set to work and wrote 100 lines of code. When Tim asked him why so many lines, Barry replied, "Its object-oriented! Each coffee bean is an object!" + +Tim, on the other hand, wrote his program in just 5 lines. As he triumphantly clicked 'Run', Barry leaned over and accidentally pressed 'Escape'. The screen flashed, and suddenly instead of coffee, Tim's program dispensed a rainy day playlist. + +Barry, holding back laughter, sarcastically said, "A splendid choice. I didnt know coffee could sing!" Tim shrugged and retorted, "Hey, at least my error messages have good taste!" + +Determined to win, Barry decided to refactor his long code. Three hours later, he realized he accidentally created a virtual coffee shop. Tim noticed and exclaimed, "Congratulations! You just coded the next big bug!" + +As Barry watched customers unintentionally brew coffee in their own chaos, he sighed, "I guess thats C++ for you; it gives you too many options! + +Tim chimed in, "And C# gives you a stable relationship! No leaks, no crashesjust pure caffeine bliss!" They both burst into laughter, declaring it a tie. + +In the end, they realized programming languages were like coffee: everyone has their favorite blend, and it's best enjoyed with good friends. So, they made a deal. From that day on, they would brew coffee together and roast each other's code, all while enjoying a good laugh. And thus, the legacy of the Coffee Code Crossover was born! +*/ \ No newline at end of file diff --git a/src/windows/main_window.cpp b/src/windows/main_window.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/windows/register_window.cpp b/src/windows/register_window.cpp new file mode 100644 index 0000000..e2b8fcd --- /dev/null +++ b/src/windows/register_window.cpp @@ -0,0 +1,50 @@ +#include "../../include/windows/register_window.h" +#include +#include +#include +#include +#include + +RegisterWindow::RegisterWindow(QWidget* parent) + : BaseWindow(WindowType::Login, parent), + usernameInput(new QLineEdit(this)), + passwordInput(new QLineEdit(this)), + registerButton(new QPushButton("Register", this)) { + initialize();} + +void RegisterWindow::initialize() { + setupUI(); + createConnections(); +} + +void RegisterWindow::setupUI() { + QVBoxLayout* layout = new QVBoxLayout(this); + + layout->addWidget(new QLabel("Username:", this)); + layout->addWidget(usernameInput); + + layout->addWidget(new QLabel("Password:", this)); + passwordInput->setEchoMode(QLineEdit::Password); + layout->addWidget(passwordInput); + + layout->addWidget(registerButton); + + setLayout(layout); +} + +void RegisterWindow::createConnections() { + connect(registerButton, &QPushButton::clicked, this, &RegisterWindow::onRegisterClicked); +} + +void RegisterWindow::onRegisterClicked() { + QString username = usernameInput->text(); + QString password = passwordInput->text(); + + if (username.isEmpty() || password.isEmpty()) { + QMessageBox::warning(this, "Error", "Username and password cannot be empty!"); + } + else { + QMessageBox::information(this, "Success", "Registration successful!"); + std::cout << "Success"; + } +} \ No newline at end of file diff --git a/src/windows/settings_window.cpp b/src/windows/settings_window.cpp new file mode 100644 index 0000000..e69de29