diff --git a/CMakeLists.txt b/CMakeLists.txt
index 63f116c..3b9f8b1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,7 +33,8 @@ target_include_directories(Habbit PRIVATE src)
target_include_directories(HabbitWinWidget PRIVATE src)
qt_add_resources(APP_RESOURCES assets/resources.qrc)
-target_sources(Habbit PRIVATE ${APP_RESOURCES})
+qt_add_resources(THEMES themes/themes.qrc)
+target_sources(Habbit PRIVATE ${APP_RESOURCES} ${THEMES})
target_link_libraries(Habbit PRIVATE Qt6::Widgets Qt6::Sql)
target_link_libraries(HabbitWinWidget PRIVATE Qt6::Widgets Qt6::Sql)
\ No newline at end of file
diff --git a/assets/icons/blue/calendar.svg b/assets/icons/blue/calendar.svg
new file mode 100644
index 0000000..a9473f9
--- /dev/null
+++ b/assets/icons/blue/calendar.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/assets/icons/blue/event.svg b/assets/icons/blue/event.svg
new file mode 100644
index 0000000..cd5a8ef
--- /dev/null
+++ b/assets/icons/blue/event.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/assets/icons/blue/habit.svg b/assets/icons/blue/habit.svg
new file mode 100644
index 0000000..7dc1b0e
--- /dev/null
+++ b/assets/icons/blue/habit.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/assets/icons/blue/home.svg b/assets/icons/blue/home.svg
new file mode 100644
index 0000000..94288a0
--- /dev/null
+++ b/assets/icons/blue/home.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/assets/icons/blue/pomodoro.svg b/assets/icons/blue/pomodoro.svg
new file mode 100644
index 0000000..fe47117
--- /dev/null
+++ b/assets/icons/blue/pomodoro.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/assets/icons/blue/setting.svg b/assets/icons/blue/setting.svg
new file mode 100644
index 0000000..a7c6815
--- /dev/null
+++ b/assets/icons/blue/setting.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/assets/icons/blue/timeline.svg b/assets/icons/blue/timeline.svg
new file mode 100644
index 0000000..8fbe1df
--- /dev/null
+++ b/assets/icons/blue/timeline.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/assets/resources.qrc b/assets/resources.qrc
index 073bc89..6f18024 100644
--- a/assets/resources.qrc
+++ b/assets/resources.qrc
@@ -1,6 +1,5 @@
- icons/default/
images/logo.png
images/add.png
images/delete.png
@@ -11,6 +10,20 @@
images/backward.png
images/active.png
images/inactive.png
+ icons/default/calendar.svg
+ icons/default/event.svg
+ icons/default/habit.svg
+ icons/default/home.svg
+ icons/default/pomodoro.svg
+ icons/default/setting.svg
+ icons/default/timeline.svg
+ icons/blue/calendar.svg
+ icons/blue/event.svg
+ icons/blue/habit.svg
+ icons/blue/home.svg
+ icons/blue/pomodoro.svg
+ icons/blue/setting.svg
+ icons/blue/timeline.svg
json_style/
diff --git a/assets/themes/blue.json b/assets/themes/blue.json
new file mode 100644
index 0000000..3a89998
--- /dev/null
+++ b/assets/themes/blue.json
@@ -0,0 +1,46 @@
+{
+ "normal": {
+ "background": "#f0f9ff",
+ "border": "1.5px solid #91d5ff",
+ "border_radius": "8",
+ "text_color": "#0000FF",
+ "font_size": "16",
+ "font_family": "Arial",
+ "padding_vertical": "0",
+ "padding_horizontal": "12",
+ "hover_background": "#cceeff",
+ "icons": {
+ "home": ":/assets/icons/blue/home.svg",
+ "habit": ":/assets/icons/blue/habit.svg",
+ "event": ":/assets/icons/blue/event.svg",
+ "pomodoro": ":/assets/icons/blue/pomodoro.svg",
+ "timeline": ":/assets/icons/blue/timeline.svg",
+ "calendar": ":/assets/icons/blue/calendar.svg",
+ "settings": ":/assets/icons/blue/setting.svg"
+ },
+ "icon_width": "24",
+ "icon_height": "24"
+ },
+ "selected": {
+ "background": "#1890ff",
+ "border": "2px solid #096dd9",
+ "border_radius": "8",
+ "text_color": "#ffffff",
+ "font_size": "18",
+ "font_family": "Arial",
+ "padding_vertical": "0",
+ "padding_horizontal": "12",
+ "hover_background": "#096dd9",
+ "icons": {
+ "home": ":/assets/icons/blue/home.svg",
+ "habit": ":/assets/icons/blue/habit.svg",
+ "event": ":/assets/icons/blue/event.svg",
+ "pomodoro": ":/assets/icons/blue/pomodoro.svg",
+ "timeline": ":/assets/icons/blue/timeline.svg",
+ "calendar": ":/assets/icons/blue/calendar.svg",
+ "settings": ":/assets/icons/blue/setting.svg"
+ },
+ "icon_width": "28",
+ "icon_height": "28"
+ }
+}
\ No newline at end of file
diff --git a/assets/themes/default.json b/assets/themes/default.json
index 6531390..96d86c7 100644
--- a/assets/themes/default.json
+++ b/assets/themes/default.json
@@ -3,20 +3,20 @@
"background": "#e6f4ff",
"border": "1.5px solid #1890ff",
"border_radius": "8",
- "text_color": "#1890ff",
+ "text_color": "#ff005c",
"font_size": "16",
"font_family": "Arial",
"padding_vertical": "0",
"padding_horizontal": "12",
"hover_background": "#bae0ff",
"icons": {
- "home": ":assets/icons/default/home.svg",
- "habit": ":assets/icons/default/habit.svg",
- "event": ":assets/icons/default/event.svg",
- "pomodoro": ":assets/icons/default/pomodoro.svg",
- "timeline": ":assets/icons/default/timeline.svg",
- "calendar": ":assets/icons/default/calendar.svg",
- "settings": ":assets/icons/default/setting.svg"
+ "home": ":/assets/icons/default/home.svg",
+ "habit": ":/assets/icons/default/habit.svg",
+ "event": ":/assets/icons/default/event.svg",
+ "pomodoro": ":/assets/icons/default/pomodoro.svg",
+ "timeline": ":/assets/icons/default/timeline.svg",
+ "calendar": ":/assets/icons/default/calendar.svg",
+ "settings": ":/assets/icons/default/setting.svg"
},
"icon_width": "24",
"icon_height": "24"
@@ -32,13 +32,13 @@
"padding_horizontal": "12",
"hover_background": "#096dd9",
"icons": {
- "home": ":assets/icons/default/home.svg",
- "habit": ":assets/icons/default/habit.svg",
- "event": ":assets/icons/default/event.svg",
- "pomodoro": ":assets/icons/default/pomodoro.svg",
- "timeline": ":assets/icons/default/timeline.svg",
- "calendar": ":assets/icons/default/calendar.svg",
- "settings": ":assets/icons/default/setting.svg"
+ "home": ":/assets/icons/default/home.svg",
+ "habit": ":/assets/icons/default/habit.svg",
+ "event": ":/assets/icons/default/event.svg",
+ "pomodoro": ":/assets/icons/default/pomodoro.svg",
+ "timeline": ":/assets/icons/default/timeline.svg",
+ "calendar": ":/assets/icons/default/calendar.svg",
+ "settings": ":/assets/icons/default/setting.svg"
},
"icon_width": "28",
"icon_height": "28"
diff --git a/assets/themes/themes.qrc b/assets/themes/themes.qrc
new file mode 100644
index 0000000..66a5c2a
--- /dev/null
+++ b/assets/themes/themes.qrc
@@ -0,0 +1,7 @@
+
+
+ blue.json
+ default.json
+ themes.json
+
+
\ No newline at end of file
diff --git a/src/DBLayer.cpp b/src/DBLayer.cpp
index bc5ce5c..324e338 100644
--- a/src/DBLayer.cpp
+++ b/src/DBLayer.cpp
@@ -6,9 +6,6 @@
DBLayer::DBLayer(std::string db_file_name) : db_file_name_(std::move(db_file_name))
{
- // 调试:输出可用数据库驱动
- qDebug() << "可用数据库驱动:" << QSqlDatabase::drivers();
- qDebug() << "准备使用数据库文件:" << QString::fromStdString(db_file_name_);
// 初始化 SQLite 数据库连接
db_ = QSqlDatabase::addDatabase("QSQLITE");
db_.setDatabaseName(QString::fromStdString(db_file_name_));
@@ -118,23 +115,6 @@ DBLayer::DBLayer(std::string db_file_name) : db_file_name_(std::move(db_file_nam
qDebug() << "UserSettingsTable 创建成功";
}
- // 创建 PomodoroStateTable 用于存储番茄钟状态
- QString pomodoroStateSql = "CREATE TABLE IF NOT EXISTS PomodoroStateTable ("
- "userId INTEGER PRIMARY KEY, "
- "state INTEGER, "
- "totalSeconds INTEGER, "
- "remainingSeconds INTEGER, "
- "remark TEXT, "
- "startTime TEXT)";
- if (!query.exec(pomodoroStateSql))
- {
- qDebug() << "PomodoroStateTable 创建失败:" << query.lastError().text();
- }
- else
- {
- qDebug() << "PomodoroStateTable 创建成功";
- }
-
// 构造函数中初始化完后关闭数据库
closeDatabase();
}
@@ -146,15 +126,11 @@ DBLayer::~DBLayer()
bool DBLayer::openDatabase() const
{
- qDebug() << "[openDatabase] 当前数据库文件:" << db_.databaseName();
if (db_.isOpen())
{
- qDebug() << "[openDatabase] 数据库已打开";
return true;
}
- bool ok = db_.open();
- qDebug() << "[openDatabase] 尝试打开数据库,结果:" << ok << ", 错误信息:" << db_.lastError().text();
- return ok;
+ return db_.open();
}
void DBLayer::closeDatabase() const
@@ -775,7 +751,7 @@ std::size_t DBLayer::getCurrentUserID() const
currentUserId = query.value("userId").toULongLong();
}
- // 不在这里关闭数据库,让调用者决定何时关闭
+ closeDatabase();
return currentUserId;
}
@@ -840,144 +816,3 @@ bool DBLayer::setActiveHabit(std::size_t habit_id)
closeDatabase();
return true;
}
-
-
-bool DBLayer::savePomodoroState(int state, int total_seconds, int remaining_seconds, const std::string& remark, const std::string& start_time)
-{
- if (!openDatabase())
- {
- //qDebug() << "数据库打开失败,无法保存番茄钟状态";
- return false;
- }
-
- std::size_t currentUserId = getCurrentUserID();
- if (currentUserId == 0)
- {
- // 如果没有登录用户,使用默认用户ID 1
- currentUserId = 1;
- //qDebug() << "没有当前登录用户,使用默认用户ID:" << currentUserId;
- }
-
- // 确保数据库连接仍然打开
- if (!db_.isOpen()) {
- //qDebug() << "数据库连接已关闭,重新打开";
- if (!openDatabase()) {
- //qDebug() << "重新打开数据库失败";
- return false;
- }
- }
-
- QSqlQuery query(db_);
- query.prepare("INSERT OR REPLACE INTO PomodoroStateTable "
- "(userId, state, totalSeconds, remainingSeconds, remark, startTime) "
- "VALUES (:userId, :state, :totalSeconds, :remainingSeconds, :remark, :startTime)");
-
- query.bindValue(":userId", static_cast(currentUserId));
- query.bindValue(":state", state);
- query.bindValue(":totalSeconds", total_seconds);
- query.bindValue(":remainingSeconds", remaining_seconds);
- query.bindValue(":remark", QString::fromStdString(remark));
- query.bindValue(":startTime", QString::fromStdString(start_time));
-
- if (!query.exec())
- {
- //qDebug() << "保存番茄钟状态失败:" << query.lastError().text();
- closeDatabase();
- return false;
- }
-
- closeDatabase();
- return true;
-}
-
-bool DBLayer::loadPomodoroState(int& state, int& total_seconds, int& remaining_seconds, std::string& remark, std::string& start_time)
-{
- if (!openDatabase())
- {
- //qDebug() << "数据库打开失败,无法加载番茄钟状态";
- return false;
- }
-
- std::size_t currentUserId = getCurrentUserID();
- if (currentUserId == 0)
- {
- // 如果没有登录用户,使用默认用户ID 1
- currentUserId = 1;
- //qDebug() << "没有当前登录用户,使用默认用户ID:" << currentUserId;
- }
-
- // 确保数据库连接仍然打开
- if (!db_.isOpen()) {
- //qDebug() << "数据库连接已关闭,重新打开";
- if (!openDatabase()) {
- //qDebug() << "重新打开数据库失败";
- return false;
- }
- }
-
- QSqlQuery query(db_);
- query.prepare("SELECT state, totalSeconds, remainingSeconds, remark, startTime "
- "FROM PomodoroStateTable WHERE userId = :userId");
- query.bindValue(":userId", static_cast(currentUserId));
-
- if (!query.exec())
- {
- //qDebug() << "查询番茄钟状态失败:" << query.lastError().text();
- closeDatabase();
- return false;
- }
-
- if (query.next())
- {
- state = query.value("state").toInt();
- total_seconds = query.value("totalSeconds").toInt();
- remaining_seconds = query.value("remainingSeconds").toInt();
- remark = query.value("remark").toString().toStdString();
- start_time = query.value("startTime").toString().toStdString();
- closeDatabase();
- return true;
- }
-
- closeDatabase();
- return false; // 没有找到保存的状态
-}
-
-bool DBLayer::clearPomodoroState()
-{
- if (!openDatabase())
- {
- //qDebug() << "数据库打开失败,无法清除番茄钟状态";
- return false;
- }
-
- std::size_t currentUserId = getCurrentUserID();
- if (currentUserId == 0)
- {
- // 如果没有登录用户,使用默认用户ID 1
- currentUserId = 1;
- //qDebug() << "没有当前登录用户,使用默认用户ID:" << currentUserId;
- }
-
- // 确保数据库连接仍然打开
- if (!db_.isOpen()) {
- //qDebug() << "数据库连接已关闭,重新打开";
- if (!openDatabase()) {
- //qDebug() << "重新打开数据库失败";
- return false;
- }
- }
-
- QSqlQuery query(db_);
- query.prepare("DELETE FROM PomodoroStateTable WHERE userId = :userId");
- query.bindValue(":userId", static_cast(currentUserId));
-
- if (!query.exec())
- {
- //qDebug() << "清除番茄钟状态失败:" << query.lastError().text();
- closeDatabase();
- return false;
- }
-
- closeDatabase();
- return true;
-}
\ No newline at end of file
diff --git a/src/DBLayer.h b/src/DBLayer.h
index 4db27bc..8ef3906 100644
--- a/src/DBLayer.h
+++ b/src/DBLayer.h
@@ -218,37 +218,6 @@ class DBLayer
*/
[[nodiscard]] std::size_t getCurrentUserID() const;
- /**
- * @brief 保存番茄钟状态
- * @author 遥远
- * @param state 番茄钟状态(0-停止,1-工作,2-休息)
- * @param total_seconds 总时长(秒)
- * @param remaining_seconds 剩余时长(秒)
- * @param remark 备注信息
- * @param start_time 开始时间
- * @return 保存是否成功
- */
- bool savePomodoroState(int state, int total_seconds, int remaining_seconds, const std::string& remark, const std::string& start_time);
-
- /**
- * @brief 加载番茄钟状态
- * @author 遥远
- * @param state 番茄钟状态(输出参数)
- * @param total_seconds 总时长(输出参数)
- * @param remaining_seconds 剩余时长(输出参数)
- * @param remark 备注信息(输出参数)
- * @param start_time 开始时间(输出参数)
- * @return 是否成功加载到状态
- */
- bool loadPomodoroState(int& state, int& total_seconds, int& remaining_seconds, std::string& remark, std::string& start_time);
-
- /**
- * @brief 清除番茄钟状态
- * @author 遥远
- * @return 清除是否成功
- */
- bool clearPomodoroState();
-
/**
* @brief 停用指定ID的习惯
* @author XTUG
diff --git a/src/PomodoroWidget.cpp b/src/PomodoroWidget.cpp
index 37abd6e..1f29b2f 100644
--- a/src/PomodoroWidget.cpp
+++ b/src/PomodoroWidget.cpp
@@ -1,58 +1,96 @@
#include "PomodoroWidget.h"
-#include
-#include
-#include
+#include"Pomodoro.h"
PomodoroWidget::PomodoroWidget(QWidget *parent)
- : QWidget(parent), state_(IDLE), total_seconds_(0), remaining_seconds_(0)
+ : QWidget(parent), state_(IDLE), total_seconds_(0), remaining_seconds_(0), pause_duration_(0)
{
- // 设置固定大小
- setFixedSize(400, 400);
-
- // 初始化圆形钟参数
- circle_radius_ = 140;
- circle_center_ = QPoint(200, 200);
-
- initCircularInterface();
- setupButtonStyles();
-
- // 初始化计时器
+ const QFont font("Microsoft YaHei", 20);
+
+ hours_edit_ = new QLineEdit("00", this);
+ minutes_edit_ = new QLineEdit("00", this);
+ seconds_edit_ = new QLineEdit("00", this);
+ control_button_ = new QPushButton("开始", this);
+ time_display_ = new QLabel("00:00:00", this);
+
+ hours_edit_->setFont(font);
+ minutes_edit_->setFont(font);
+ seconds_edit_->setFont(font);
+ control_button_->setFont(font);
+ time_display_->setFont(font);
+ time_display_->setAlignment(Qt::AlignCenter);
+
+ hours_edit_->setFixedWidth(60);
+ minutes_edit_->setFixedWidth(60);
+ seconds_edit_->setFixedWidth(60);
+
+ const auto time_layout = new QHBoxLayout;
+ time_layout->addWidget(hours_edit_);
+ time_layout->addWidget(new QLabel(":"));
+ time_layout->addWidget(minutes_edit_);
+ time_layout->addWidget(new QLabel(":"));
+ time_layout->addWidget(seconds_edit_);
+
+ const auto main_layout = new QVBoxLayout(this);
+ main_layout->addLayout(time_layout);
+ main_layout->addWidget(control_button_);
+ main_layout->addWidget(time_display_);
+
+ connect(control_button_, &QPushButton::clicked, this, &PomodoroWidget::handleControlButton);
+
timer_ = new QTimer(this);
timer_->setInterval(1000); // 每秒更新
connect(timer_, &QTimer::timeout, this, &PomodoroWidget::updateTimer);
-
- // 设置初始时间显示
- updateTimeDisplay();
- updateRemarkDisplay();
-
- // 强制重绘
- update();
}
PomodoroWidget::PomodoroWidget(const Pomodoro& pomo, QWidget* parent)
- : QWidget(parent), state_(RUNNING)
+ : QWidget(parent), state_(RUNNING), pause_duration_(0)
{
- // 设置固定大小
- setFixedSize(400, 400);
-
- // 初始化圆形钟参数
- circle_radius_ = 140;
- circle_center_ = QPoint(200, 200);
-
- initCircularInterface();
- setupButtonStyles();
-
+ const QFont font("Microsoft YaHei", 20);
+
+ hours_edit_ = new QLineEdit("00", this);
+ minutes_edit_ = new QLineEdit("00", this);
+ seconds_edit_ = new QLineEdit("00", this);
+ control_button_ = new QPushButton("暂停", this);
+ time_display_ = new QLabel("00:00:00", this);
+
+ hours_edit_->setFont(font);
+ minutes_edit_->setFont(font);
+ seconds_edit_->setFont(font);
+ control_button_->setFont(font);
+ time_display_->setFont(font);
+ time_display_->setAlignment(Qt::AlignCenter);
+
+ hours_edit_->setFixedWidth(60);
+ minutes_edit_->setFixedWidth(60);
+ seconds_edit_->setFixedWidth(60);
+
+ const auto time_layout = new QHBoxLayout;
+ time_layout->addWidget(hours_edit_);
+ time_layout->addWidget(new QLabel(":"));
+ time_layout->addWidget(minutes_edit_);
+ time_layout->addWidget(new QLabel(":"));
+ time_layout->addWidget(seconds_edit_);
+
+ const auto main_layout = new QVBoxLayout(this);
+ main_layout->addLayout(time_layout);
+ main_layout->addWidget(control_button_);
+ main_layout->addWidget(time_display_);
+
// 设置初始时间
int h = std::chrono::duration_cast(pomo.pomodoro_time.to_duration()).count();
int m = std::chrono::duration_cast(pomo.pomodoro_time.to_duration()).count() % 60;
int s = std::chrono::duration_cast(pomo.pomodoro_time.to_duration()).count() % 60;
+ hours_edit_->setText(QString::number(h).rightJustified(2, '0'));
+ minutes_edit_->setText(QString::number(m).rightJustified(2, '0'));
+ seconds_edit_->setText(QString::number(s).rightJustified(2, '0'));
total_seconds_ = h * 3600 + m * 60 + s;
remaining_seconds_ = total_seconds_;
start_time_ = QTime::currentTime();
remark_ = QString::fromStdString(pomo.record);
- // 初始化计时器
+ connect(control_button_, &QPushButton::clicked, this, &PomodoroWidget::handleControlButton);
+
timer_ = new QTimer(this);
timer_->setInterval(1000); // 每秒更新
connect(timer_, &QTimer::timeout, this, &PomodoroWidget::updateTimer);
@@ -98,25 +136,25 @@ void PomodoroWidget::initCircularInterface()
image_button_ = new QPushButton("📷", top_container);
image_button_->setFixedSize(30, 30);
image_button_->setStyleSheet("QPushButton { border: none; background: transparent; font-size: 25px; }");
-
+
music_button_ = new QPushButton("🎵", top_container);
music_button_->setFixedSize(30, 30);
music_button_->setStyleSheet("QPushButton { border: none; background: transparent; font-size: 25px; }");
-
+
top_layout->addStretch();
top_layout->addWidget(image_button_);
top_layout->addWidget(music_button_);
top_layout->addStretch();
-
+
// 创建备注显示区域
QWidget* remark_container = new QWidget(circle_container);
remark_container->setFixedHeight(15);
remark_container->setStyleSheet("background: transparent;");
-
+
QVBoxLayout* remark_layout = new QVBoxLayout(remark_container);
remark_layout->setContentsMargins(0, 0, 0, 0);
remark_layout->setSpacing(0);
-
+
remark_label_ = new QLabel("", remark_container);
remark_label_->setAlignment(Qt::AlignCenter);
remark_label_->setStyleSheet(
@@ -129,16 +167,16 @@ void PomodoroWidget::initCircularInterface()
"}"
);
remark_layout->addWidget(remark_label_, 0, Qt::AlignCenter);
-
+
// 创建中间时间显示容器 - 占据更多空间
QWidget* time_container = new QWidget(circle_container);
time_container->setFixedHeight(220);
time_container->setStyleSheet("background: transparent;");
-
+
QVBoxLayout* time_layout = new QVBoxLayout(time_container);
time_layout->setContentsMargins(0, 0, 0, 0);
time_layout->setSpacing(20);
-
+
// 时间输入框(可编辑)
time_edit_ = new QLineEdit("00 : 00 : 00", time_container);
time_edit_->setAlignment(Qt::AlignCenter);
@@ -154,7 +192,7 @@ void PomodoroWidget::initCircularInterface()
" margin-top: -5px;"
"}"
);
-
+
// 时间显示标签(只读)
time_display_ = new QLabel("00 : 00 : 00", time_container);
time_display_->setAlignment(Qt::AlignCenter);
@@ -169,25 +207,25 @@ void PomodoroWidget::initCircularInterface()
"}"
);
time_display_->hide(); // 初始隐藏,显示输入框
-
+
time_layout->addStretch();
time_layout->addWidget(time_edit_, 0, Qt::AlignCenter);
time_layout->addWidget(time_display_, 0, Qt::AlignCenter);
time_layout->addStretch();
-
+
// 创建底部按钮容器 - 更靠近时间显示
QWidget* bottom_container = new QWidget(circle_container);
bottom_container->setFixedHeight(50);
bottom_container->setStyleSheet("background: transparent;");
-
+
QHBoxLayout* bottom_layout = new QHBoxLayout(bottom_container);
bottom_layout->setContentsMargins(0, 0, 0, 0);
bottom_layout->setSpacing(50);
-
+
control_button_ = new QPushButton("▶", bottom_container);
control_button_->setFixedSize(35, 35);
control_button_->setStyleSheet("QPushButton { border: none; background: transparent; font-size: 30px; }");
-
+
reset_button_ = new QPushButton("🔄", bottom_container);
reset_button_->setFixedSize(30, 30);
reset_button_->setStyleSheet("QPushButton { border: none; background: transparent; font-size: 25px; }");
@@ -316,212 +354,78 @@ void PomodoroWidget::setupButtonStyles()
if (music_button_) music_button_->setStyleSheet(music_button_->styleSheet() + hover_style);
if (control_button_) control_button_->setStyleSheet(control_button_->styleSheet() + hover_style);
if (reset_button_) reset_button_->setStyleSheet(reset_button_->styleSheet() + hover_style);
+ control_button_->setText("暂停");
}
void PomodoroWidget::handleControlButton()
{
- if (state_ == IDLE) {
- // 检查是否已设置时间
+ switch (state_) {
+ case IDLE: {
+ const int h = hours_edit_->text().toInt();
+ const int m = minutes_edit_->text().toInt();
+ const int s = seconds_edit_->text().toInt();
+ total_seconds_ = h * 3600 + m * 60 + s;
+
if (total_seconds_ == 0) {
- QMessageBox::warning(this, "提示", "请先设置时间!");
+ QMessageBox::warning(this, "错误", "时间不能为零!");
return;
}
-
- // 输入备注
+
bool ok;
- QString remark = QInputDialog::getText(this, "输入备注", "请输入备注信息:", QLineEdit::Normal, "", &ok);
+ const QString input = QInputDialog::getText(this, "备注", "请输入番茄钟备注:", QLineEdit::Normal, "", &ok);
if (!ok) return;
-
- if (remark.trimmed().isEmpty()) {
- QMessageBox::warning(this, "提示", "备注不能为空!");
- return;
- }
-
- remark_ = remark.trimmed();
- updateRemarkDisplay();
-
- // 开始计时
+ remark_ = input;
+
+ remaining_seconds_ = total_seconds_;
+ start_time_ = QTime::currentTime();
timer_->start();
state_ = RUNNING;
- control_button_->setText("⏸");
-
- // 切换到只读显示模式
- time_edit_->hide();
- time_display_->show();
- time_display_->setText(formatTime(remaining_seconds_));
-
- // 发出状态改变信号
- emit stateChanged();
-
- } else if (state_ == RUNNING) {
- // 暂停
+ control_button_->setText("暂停");
+ break;
+ }
+ case RUNNING:
+ pause_start_ = QTime::currentTime();
timer_->stop();
state_ = PAUSED;
- control_button_->setText("▶");
-
- // 发出状态改变信号
- emit stateChanged();
-
- } else if (state_ == PAUSED) {
- // 继续
+ control_button_->setText("继续");
+ break;
+ case PAUSED:
+ pause_duration_ += pause_start_.secsTo(QTime::currentTime());
timer_->start();
state_ = RUNNING;
- control_button_->setText("⏸");
-
- // 发出状态改变信号
- emit stateChanged();
- }
-
- update();
-}
-
-void PomodoroWidget::handleResetButton()
-{
- // 重置所有状态
- timer_->stop();
- state_ = IDLE;
- total_seconds_ = 0;
- remaining_seconds_ = 0;
- remark_.clear();
-
- // 重置UI
- control_button_->setText("▶");
- time_edit_->setText("00 : 00 : 00");
- time_edit_->show();
- time_display_->hide();
- updateRemarkDisplay();
-
- update();
-
- // 发出状态改变信号
- emit stateChanged();
-}
-
-void PomodoroWidget::handleTimeEditFinished()
-{
- QString time_text = time_edit_->text();
- int hours, minutes, seconds;
-
- if (parseTimeInput(time_text, hours, minutes, seconds)) {
- total_seconds_ = hours * 3600 + minutes * 60 + seconds;
- remaining_seconds_ = total_seconds_;
- time_edit_->setText(formatTime(total_seconds_));
- } else {
- QMessageBox::warning(this, "格式错误", "时间格式不正确!请使用 HH:MM:SS 格式");
- time_edit_->setText("00 : 00 : 00");
- total_seconds_ = 0;
- remaining_seconds_ = 0;
+ control_button_->setText("暂停");
+ break;
}
}
void PomodoroWidget::updateTimer()
{
- if (state_ == RUNNING) {
- if (remaining_seconds_ > 0) {
- remaining_seconds_--;
- time_display_->setText(formatTime(remaining_seconds_));
- update();
- emit timerUpdated();
- }
- if (remaining_seconds_ <= 0) {
- remaining_seconds_ = 0;
- timer_->stop();
- state_ = IDLE;
- control_button_->setText("▶");
- QMessageBox::information(this, "时间到", "番茄钟时间到!");
- emit stateChanged();
- }
- }
-}
+ const int elapsed = start_time_.secsTo(QTime::currentTime()) - pause_duration_;
+ remaining_seconds_ = total_seconds_ - elapsed;
-void PomodoroWidget::updateTimeDisplay()
-{
- if (time_edit_) {
- time_edit_->setText(formatTime(total_seconds_));
- }
- if (time_display_) {
- time_display_->setText(formatTime(remaining_seconds_));
+ if (remaining_seconds_ <= 0) {
+ timer_->stop();
+ handleTimeUp();
+ return;
}
-}
-void PomodoroWidget::updateRemarkDisplay()
-{
- if (remark_label_) {
- remark_label_->setText(remark_);
- }
-}
+ const int h = remaining_seconds_ / 3600;
+ const int m = remaining_seconds_ % 3600 / 60;
+ const int s = remaining_seconds_ % 60;
-bool PomodoroWidget::parseTimeInput(const QString& input, int& hours, int& minutes, int& seconds)
-{
- QStringList parts = input.split(":");
- if (parts.size() != 3) return false;
-
- bool ok1, ok2, ok3;
- hours = parts[0].trimmed().toInt(&ok1);
- minutes = parts[1].trimmed().toInt(&ok2);
- seconds = parts[2].trimmed().toInt(&ok3);
-
- if (!ok1 || !ok2 || !ok3) return false;
- if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) return false;
-
- return true;
+ time_display_->setText(QString("%1:%2:%3")
+ .arg(h, 2, 10, QLatin1Char('0'))
+ .arg(m, 2, 10, QLatin1Char('0'))
+ .arg(s, 2, 10, QLatin1Char('0')));
}
-QString PomodoroWidget::formatTime(int total_seconds) const
+void PomodoroWidget::handleTimeUp()
{
- int hours = total_seconds / 3600;
- int minutes = (total_seconds % 3600) / 60;
- int seconds = total_seconds % 60;
-
- return QString("%1 : %2 : %3")
- .arg(hours, 2, 10, QChar('0'))
- .arg(minutes, 2, 10, QChar('0'))
- .arg(seconds, 2, 10, QChar('0'));
-}
-
-void PomodoroWidget::handleImageButton()
-{
- // 图片按钮功能(待实现)
- QMessageBox::information(this, "图片", "图片功能待实现");
-}
-
-void PomodoroWidget::handleMusicButton()
-{
- // 音乐按钮功能(待实现)
- QMessageBox::information(this, "音乐", "音乐功能待实现");
-}
-
-QString PomodoroWidget::getTimeDisplayText() const
-{
- if (state_ == IDLE) {
- return "00 : 00 : 00";
- }
- return formatTime(remaining_seconds_);
-}
-
-void PomodoroWidget::restoreState(int state, int total_seconds, int remaining_seconds, const QString& remark, const QString& /*start_time*/)
-{
- if (timer_) timer_->stop();
- state_ = static_cast(state);
- total_seconds_ = total_seconds;
- remaining_seconds_ = remaining_seconds;
- remark_ = remark;
- start_time_ = QTime::currentTime(); // 仅用于兼容,不参与倒计时计算
-
- if (state_ == IDLE) {
- control_button_->setText("▶");
- time_edit_->setText("00 : 00 : 00");
- time_edit_->show();
- time_display_->hide();
- } else {
- control_button_->setText(state_ == RUNNING ? "⏸" : "▶");
- time_edit_->hide();
- time_display_->show();
- time_display_->setText(formatTime(remaining_seconds_));
- if (state_ == RUNNING) timer_->start();
- }
- updateRemarkDisplay();
- update();
- emit stateChanged();
+ QMessageBox::information(this, "时间到", QString("番茄钟已完成!\n备注:%1").arg(remark_));
+ state_ = IDLE;
+ control_button_->setText("开始");
+ remaining_seconds_ = 0;
+ pause_duration_ = 0;
+ time_display_->setText("00:00:00");
}
diff --git a/src/PomodoroWidget.h b/src/PomodoroWidget.h
index 842688a..21d7c65 100644
--- a/src/PomodoroWidget.h
+++ b/src/PomodoroWidget.h
@@ -8,88 +8,78 @@
#ifndef POMODOROWIDGET_H
#define POMODOROWIDGET_H
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
#include
+#include
#include
-#include
-#include
-#include
+#include
+#include
#include "Pomodoro.h"
-class PomodoroWidget : public QWidget
+/**
+ * @class PomodoroWidget
+ * @brief 实现番茄钟计时器功能的Qt控件
+ */
+class PomodoroWidget final : public QWidget
{
- Q_OBJECT
+Q_OBJECT
public:
- enum State {
- IDLE, // 空闲状态
- RUNNING, // 运行状态
- PAUSED // 暂停状态
- };
-
- explicit PomodoroWidget(QWidget *parent = nullptr);
+ /**
+ * @brief 构造函数,初始化番茄钟控件
+ * @param parent 父窗口部件,默认为nullptr
+ */
+ explicit PomodoroWidget(QWidget* parent = nullptr);
+ /**
+ * @brief 新增:根据番茄钟数据初始化
+ */
explicit PomodoroWidget(const Pomodoro& pomo, QWidget* parent = nullptr);
-
- // 公共方法,供外部获取状态和信息
- State getState() const { return state_; }
- QString getRemark() const { return remark_; }
- QString getTimeDisplayText() const;
- int getRemainingSeconds() const { return remaining_seconds_; }
- int getTotalSeconds() const { return total_seconds_; }
-
- // 恢复番茄钟状态
- void restoreState(int state, int total_seconds, int remaining_seconds, const QString& remark, const QString& start_time);
-
-signals:
- void stateChanged(); // 状态改变信号
- void timerUpdated(); // 定时器更新信号
-
-protected:
- void paintEvent(QPaintEvent* event) override;
private slots:
- void handleImageButton();
- void handleMusicButton();
+ /**
+ * @brief 处理控制按钮点击事件
+ */
void handleControlButton();
- void handleResetButton();
- void handleTimeEditFinished();
- void updateTimer();
-private:
+ /**
+ * @brief 更新计时器显示
+ */
+ void updateTimer();
- State state_;
- int total_seconds_;
- int remaining_seconds_;
- QTimer* timer_;
- QTime start_time_;
- QString remark_;
+ /**
+ * @brief 处理时间到事件
+ */
+ void handleTimeUp();
- // UI组件
- QPushButton* image_button_;
- QPushButton* music_button_;
- QPushButton* control_button_;
- QPushButton* reset_button_;
- QLineEdit* time_edit_; // 时间输入框
- QLabel* remark_label_; // 备注显示标签
- QLabel* time_display_; // 时间显示标签
+private:
+ /**
+ * @enum State
+ * @brief 定义番茄钟的状态
+ */
+ enum State
+ {
+ IDLE, /**< 空闲状态 */
+ RUNNING,/**< 运行状态 */
+ PAUSED /**< 暂停状态 */
+ };
- // 圆形钟参数
- int circle_radius_;
- QPoint circle_center_;
+ State state_; /**< 当前番茄钟状态 */
+ QTimer* timer_; /**< Qt计时器对象 */
+ QTime start_time_; /**< 开始时间 */
+ int total_seconds_; /**< 总秒数 */
+ int remaining_seconds_; /**< 剩余秒数 */
+ int pause_duration_; /**< 暂停持续时间 */
+ QTime pause_start_; /**< 暂停开始时间 */
- // 私有方法
- void initCircularInterface();
- void setupButtonStyles();
- void updateTimeDisplay();
- void updateRemarkDisplay();
- bool parseTimeInput(const QString& input, int& hours, int& minutes, int& seconds);
- QString formatTime(int total_seconds) const;
+ QLineEdit* hours_edit_; /**< 小时输入框 */
+ QLineEdit* minutes_edit_; /**< 分钟输入框 */
+ QLineEdit* seconds_edit_; /**< 秒输入框 */
+ QPushButton* control_button_;/**< 控制按钮 */
+ QLabel* time_display_; /**< 时间显示标签 */
+ QString remark_; /**< 备注信息 */
};
#endif // POMODOROWIDGET_H
\ No newline at end of file
diff --git a/src/ServiceLayer.cpp b/src/ServiceLayer.cpp
index 2adf71a..160e626 100644
--- a/src/ServiceLayer.cpp
+++ b/src/ServiceLayer.cpp
@@ -4,7 +4,7 @@
#include
#include
#include
-#include
+#include
bool ServiceLayer::insertHabit(const std::string& name, const Date& start_date, const Date& end_date, std::size_t times_per_day)
@@ -305,31 +305,8 @@ QStringList ServiceLayer::getAvailableThemes()
for (const auto& value : themes) {
theme_names.append(value.toString());
}
- return theme_names;
-}
-
-bool ServiceLayer::savePomodoroState(int state, int total_seconds, int remaining_seconds, const std::string& remark, const std::string& start_time)
-{
- // 参数验证
- if (state < 0 || state > 2 || total_seconds <= 0 || remaining_seconds < 0 || remaining_seconds > total_seconds)
- {
- return false;
- }
- // 调用数据库层保存番茄钟状态
- return this->db_layer.savePomodoroState(state, total_seconds, remaining_seconds, remark, start_time);
-}
-
-bool ServiceLayer::loadPomodoroState(int& state, int& total_seconds, int& remaining_seconds, std::string& remark, std::string& start_time)
-{
- // 调用数据库层加载番茄钟状态
- return this->db_layer.loadPomodoroState(state, total_seconds, remaining_seconds, remark, start_time);
-}
-
-bool ServiceLayer::clearPomodoroState()
-{
- // 调用数据库层清除番茄钟状态
- return this->db_layer.clearPomodoroState();
+ return theme_names;
}
QString ServiceLayer::getCurrentThemeName()
diff --git a/src/ServiceLayer.h b/src/ServiceLayer.h
index 62187f9..35582a2 100644
--- a/src/ServiceLayer.h
+++ b/src/ServiceLayer.h
@@ -162,7 +162,7 @@ class ServiceLayer
bool pomodoroTick(const Pomodoro& pomodoro, const Time& count_time);
/**
- * @brief 获取指定日期的习惯打卡记录统计
+ * @brief 获取指定月份的习惯打卡记录统计
* @author Rain
* @param date 指定日期(使用其年月部分)
* @return 每月每天的实际打卡数和应当打卡数
@@ -241,37 +241,6 @@ class ServiceLayer
* @return 主题配置的JSON对象
*/
static QJsonObject getThemeConfig(const QString &theme_name);
-
- /**
- * @brief 保存番茄钟状态到数据库
- * @author Rain
- * @param state 番茄钟状态 (0=IDLE, 1=RUNNING, 2=PAUSED)
- * @param total_seconds 总秒数
- * @param remaining_seconds 剩余秒数
- * @param remark 备注
- * @param start_time 开始时间戳
- * @return 保存是否成功
- */
- bool savePomodoroState(int state, int total_seconds, int remaining_seconds, const std::string& remark, const std::string& start_time);
-
- /**
- * @brief 从数据库加载番茄钟状态
- * @author Rain
- * @param state 输出:番茄钟状态
- * @param total_seconds 输出:总秒数
- * @param remaining_seconds 输出:剩余秒数
- * @param remark 输出:备注
- * @param start_time 输出:开始时间戳
- * @return 加载是否成功
- */
- bool loadPomodoroState(int& state, int& total_seconds, int& remaining_seconds, std::string& remark, std::string& start_time);
-
- /**
- * @brief 清除番茄钟状态
- * @author Rain
- * @return 清除是否成功
- */
- bool clearPomodoroState();
};
inline const QString ServiceLayer::THEMES_PATH = "themes/themes.json"; // 主题列表配置文件路径
diff --git a/src/ViewLayer.cpp b/src/ViewLayer.cpp
index 1bb34cf..c9d4320 100644
--- a/src/ViewLayer.cpp
+++ b/src/ViewLayer.cpp
@@ -1,16 +1,12 @@
#include
#include
+#include
#include
-#include
-#include
-#include
-#include
#include "ViewLayer.h"
#include
-#include
#include "CalendarView.h"
#include "NavigationBar.h"
-
+#include
ViewLayer::ViewLayer(QWidget *parent) : QWidget(parent),
cur_view_type(ViewType::MAIN_VIEW)
@@ -41,41 +37,6 @@ void ViewLayer::init()
initSettingsView();
resetCurrentView(ViewType::MAIN_VIEW);
-
- // 程序启动后立即检查并恢复番茄钟状态
- QTimer::singleShot(100, this, &ViewLayer::checkAndRestorePomodoroState);
-
- // 测试数据库操作
- QTimer::singleShot(500, this, [this]() {
- std::cout << "=== 测试数据库操作 ===" << std::endl;
-
- // 测试保存
- bool save_result = sv_Layer.savePomodoroState(1, 300, 250, "测试番茄钟", "2024-01-01 10:00:00");
- std::cout << "测试保存结果:" << (save_result ? "成功" : "失败") << std::endl;
-
- // 测试加载
- int state, total_seconds, remaining_seconds;
- std::string remark, start_time;
- bool load_result = sv_Layer.loadPomodoroState(state, total_seconds, remaining_seconds, remark, start_time);
- std::cout << "测试加载结果:" << (load_result ? "成功" : "失败") << std::endl;
-
- if (load_result) {
- std::cout << "加载的数据:" << std::endl;
- std::cout << " 状态:" << state << std::endl;
- std::cout << " 总时长:" << total_seconds << std::endl;
- std::cout << " 剩余时长:" << remaining_seconds << std::endl;
- std::cout << " 备注:" << remark << std::endl;
- std::cout << " 开始时间:" << start_time << std::endl;
- }
-
- // 测试清除
- bool clear_result = sv_Layer.clearPomodoroState();
- std::cout << "测试清除结果:" << (clear_result ? "成功" : "失败") << std::endl;
-
- std::cout << "=== 数据库操作测试完成 ===" << std::endl;
- // 移除自动退出逻辑,方便用户手动测试
- // QTimer::singleShot(3000, qApp, &QApplication::quit);
- });
}
void ViewLayer::resetCurrentView(ViewType view)
@@ -235,15 +196,21 @@ void ViewLayer::initEventManageView()
event_manage_widget->setLayout(layout);
}
- // 顶部标题
+ // 顶部标题 + 返回按钮
QHBoxLayout *topLayout = new QHBoxLayout();
QLabel *title = new QLabel("事项管理", event_manage_widget);
QFont titleFont;
titleFont.setPointSize(18);
titleFont.setBold(true);
title->setFont(titleFont);
+ QPushButton *backButton = new QPushButton();
+ backButton->setIcon(QIcon(":/assets/images/back.png"));
+ backButton->setIconSize(QSize(30, 30));
+ backButton->setFixedSize(45, 45);
+ connect(backButton, &QPushButton::clicked, this, &ViewLayer::onBackToNavigation);
topLayout->addWidget(title);
topLayout->addStretch();
+ topLayout->addWidget(backButton);
layout->addLayout(topLayout, 0, 0, 1, 4);
// 滚动区域和事项列表容器
@@ -315,8 +282,8 @@ void ViewLayer::initEventManageView()
cardLayout->addWidget(remindLabel);
cardLayout->addLayout(buttonLayout);
- row = i / eventsPerRow;
- col = i % eventsPerRow;
+ int row = i / eventsPerRow;
+ int col = i % eventsPerRow;
grid->addWidget(eventCard, row, col);
}
@@ -579,12 +546,11 @@ void ViewLayer::initMainView()
cardLayout->setAlignment(Qt::AlignVCenter);
cardLayout->setSpacing(16);
- // 习惯名称框
- QLabel* nameLabel = new QLabel(QString::fromStdString(habit.name));
- nameLabel->setFixedSize(120, 50);
- nameLabel->setAlignment(Qt::AlignCenter);
- nameLabel->setStyleSheet("font-weight:bold;font-size:16px;border-radius:8px;background:#fff;border:1px solid #e0e0e0;");
- nameLabel->setWordWrap(true);
+ // 编号框
+ QLabel* indexLabel = new QLabel(QString::number(index + 1));
+ indexLabel->setFixedSize(30, 50);
+ indexLabel->setAlignment(Qt::AlignCenter);
+ indexLabel->setStyleSheet("font-weight:bold;font-size:22px;border-radius:8px;background:#fff;border:1px solid #e0e0e0;");
// 日期
QLabel* dateLabel = new QLabel(
@@ -594,7 +560,26 @@ void ViewLayer::initMainView()
);
dateLabel->setStyleSheet("font-size:16px;");
-
+ // 编辑按钮
+ QPushButton* editBtn = new QPushButton();
+ editBtn->setIcon(QIcon(":/assets/images/modify.png"));
+ editBtn->setToolTip("编辑");
+ connect(editBtn, &QPushButton::clicked, [this, habit]() { habitUpdateView(habit); });
+
+ // 删除按钮
+ QPushButton* delBtn = new QPushButton();
+ delBtn->setIcon(QIcon(":/assets/images/delete.png"));
+ delBtn->setToolTip("删除");
+ connect(delBtn, &QPushButton::clicked, [this, habit]() {
+ if (QMessageBox::question(this, "确认删除", "确定删除该习惯吗?") == QMessageBox::Yes) {
+ if (sv_Layer.deleteHabit(habit.habit_id)) {
+ QMessageBox::information(this, "提示", "删除成功");
+ initMainView();
+ } else {
+ QMessageBox::warning(this, "错误", "删除失败");
+ }
+ }
+ });
// 打卡次数
QLabel* checkinLabel = new QLabel(
@@ -602,69 +587,12 @@ void ViewLayer::initMainView()
);
checkinLabel->setStyleSheet("font-size:16px;");
- // 打卡按钮
- QPushButton* checkinBtn = new QPushButton("打卡");
- checkinBtn->setFixedSize(60, 30);
- checkinBtn->setStyleSheet(
- "QPushButton {"
- " background-color: #52c41a;"
- " color: white;"
- " border: none;"
- " border-radius: 6px;"
- " font-size: 14px;"
- " font-weight: bold;"
- " padding: 2px;"
- "}"
- "QPushButton:hover {"
- " background-color: #389e0d;"
- "}"
- "QPushButton:pressed {"
- " background-color: #237804;"
- "}"
- );
-
- // 连接打卡按钮信号
- connect(checkinBtn, &QPushButton::clicked, [this, habit, checkinLabel, todayCheckin]() mutable {
- // 检查是否已达到目标次数
- if (todayCheckin >= habit.target_count) {
- QMessageBox::information(this, "打卡完成", QString("习惯「%1」今日打卡已完成!(%2/%3)").arg(QString::fromStdString(habit.name)).arg(QString::number(todayCheckin)).arg(QString::number(habit.target_count)));
- return;
- }
-
- if (sv_Layer.checkinHabit(habit)) {
- // 直接增加打卡次数
- todayCheckin++;
- checkinLabel->setText(QString("打卡:%1 / %2 次").arg(QString::number(todayCheckin)).arg(QString::number(habit.target_count)));
-
- // 检查是否完成目标
- if (todayCheckin >= habit.target_count) {
- QMessageBox::information(this, "打卡完成", QString("习惯「%1」今日打卡已完成!(%2/%3)").arg(QString::fromStdString(habit.name)).arg(QString::number(todayCheckin)).arg(QString::number(habit.target_count)));
- // 可选:禁用打卡按钮
- // checkinBtn->setEnabled(false);
- // checkinBtn->setStyleSheet(
- // "QPushButton {"
- // " background-color: #d9d9d9;"
- // " color: #999;"
- // " border: none;"
- // " border-radius: 6px;"
- // " font-size: 14px;"
- // " font-weight: bold;"
- // " padding: 2px;"
- // "}"
- // );
- } else {
- QMessageBox::information(this, "打卡成功", QString("习惯「%1」打卡成功!(%2/%3)").arg(QString::fromStdString(habit.name)).arg(QString::number(todayCheckin)).arg(QString::number(habit.target_count)));
- }
- } else {
- QMessageBox::warning(this, "打卡失败", QString("习惯「%1」打卡失败!").arg(QString::fromStdString(habit.name)));
- }
- });
-
// 横向布局
- cardLayout->addWidget(nameLabel);
+ cardLayout->addWidget(indexLabel);
cardLayout->addWidget(dateLabel);
+ cardLayout->addWidget(editBtn);
+ cardLayout->addWidget(delBtn);
cardLayout->addWidget(checkinLabel);
- cardLayout->addWidget(checkinBtn);
cardLayout->addStretch();
habitCard->setLayout(cardLayout);
@@ -691,6 +619,38 @@ void ViewLayer::initMainView()
habitGroup->setLayout(groupLayout);
gridLayout->addWidget(habitGroup, 0, 0, 2, 1);
+ // 刷新图片按钮
+ QPushButton* refreshBtn = new QPushButton(main_widget);
+ refreshBtn->setIcon(QIcon(":/assets/images/update.png"));
+ refreshBtn->setIconSize(QSize(48, 48));
+ refreshBtn->setFixedSize(60, 60);
+ refreshBtn->setStyleSheet(R"(
+ border: none;
+ background: transparent;
+ outline: none;
+ )");
+ refreshBtn->setToolTip("刷新当前页面");
+
+ QLabel* refreshLabel = new QLabel("点我更新", main_widget);
+ refreshLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
+ refreshLabel->setStyleSheet("font-size:14px; color:#888;");
+
+ // 用QWidget包裹刷新按钮和文字
+ QWidget* refreshWidget = new QWidget(main_widget);
+ QVBoxLayout* refreshLayout = new QVBoxLayout(refreshWidget);
+ refreshLayout->addWidget(refreshBtn, 0, Qt::AlignHCenter);
+ refreshLayout->addWidget(refreshLabel, 0, Qt::AlignHCenter);
+ refreshLayout->setContentsMargins(0, 0, 0, 0);
+ refreshWidget->setLayout(refreshLayout);
+
+ // 插入到主布局 habit 区下方
+ gridLayout->addWidget(refreshWidget, 2, 0, Qt::AlignLeft);
+
+ // 点击刷新
+ connect(refreshBtn, &QPushButton::clicked, [this]() {
+ initMainView(); // 直接重新初始化主视图
+ });
+
// 2. 右上:事项区
QGroupBox* eventGroup = new QGroupBox("活跃事项", main_widget);
QWidget* eventListContainer = new QWidget();
@@ -711,9 +671,24 @@ void ViewLayer::initMainView()
QLabel* nameLabel = new QLabel(QString::fromStdString(event.title));
QLabel* dateLabel = new QLabel(QString::fromStdString(toString(event.event_date)));
QLabel* timeLabel = new QLabel(QString::fromStdString(toString(event.event_time)));
+ QPushButton* editBtn = new QPushButton("编辑");
+ QPushButton* delBtn = new QPushButton("删除");
+ connect(editBtn, &QPushButton::clicked, [this, event]() { EventUpdateView(event); });
+ connect(delBtn, &QPushButton::clicked, [this, event]() {
+ if (QMessageBox::question(this, "确认删除", "确定删除该事项吗?") == QMessageBox::Yes) {
+ if (sv_Layer.deleteEvent(event.event_id)) {
+ QMessageBox::information(this, "提示", "删除成功");
+ initMainView();
+ } else {
+ QMessageBox::warning(this, "错误", "删除失败");
+ }
+ }
+ });
cardLayout->addWidget(nameLabel);
cardLayout->addWidget(dateLabel);
cardLayout->addWidget(timeLabel);
+ cardLayout->addWidget(editBtn);
+ cardLayout->addWidget(delBtn);
eventCard->setLayout(cardLayout);
eventLayout->addWidget(eventCard);
++index;
@@ -727,27 +702,26 @@ void ViewLayer::initMainView()
// 3. 右下:番茄钟区
QGroupBox* pomoGroup = new QGroupBox("当前番茄钟", main_widget);
- QVBoxLayout* pomoLayout = new QVBoxLayout(pomoGroup);
-
- // 创建番茄钟显示组件
- main_pomodoro_remark_label = new QLabel("", pomoGroup);
- main_pomodoro_remark_label->setAlignment(Qt::AlignCenter);
- main_pomodoro_remark_label->setStyleSheet("color:#333;font-size:30px;font-weight:bold;margin:5px 0;");
- main_pomodoro_remark_label->hide();
-
- main_pomodoro_time_label = new QLabel("00 : 00 : 00", pomoGroup);
- main_pomodoro_time_label->setAlignment(Qt::AlignCenter);
- main_pomodoro_time_label->setStyleSheet("color:#1890ff;font-size:20px;font-weight:bold;margin:5px 0;");
- main_pomodoro_time_label->hide();
-
- main_pomodoro_no_pomodoro_label = new QLabel("暂无番茄钟", pomoGroup);
- main_pomodoro_no_pomodoro_label->setAlignment(Qt::AlignCenter);
- main_pomodoro_no_pomodoro_label->setStyleSheet("color:#888;font-size:16px;margin:20px 0;");
-
- pomoLayout->addWidget(main_pomodoro_remark_label);
- pomoLayout->addWidget(main_pomodoro_time_label);
- pomoLayout->addWidget(main_pomodoro_no_pomodoro_label);
-
+ QHBoxLayout* pomoLayout = new QHBoxLayout(pomoGroup);
+ Date pomoToday = std::chrono::year_month_day(std::chrono::floor(std::chrono::system_clock::now()));
+ DateRecord pomoTodayRecord = sv_Layer.getAllRecordsByDate(pomoToday);
+ QLayoutItem* child;
+ while ((child = pomoLayout->takeAt(0)) != nullptr) {
+ delete child->widget();
+ delete child;
+ }
+ if (!pomoTodayRecord.pomodoro_records.empty()) {
+ pomoLayout->addStretch(1);
+ for (const auto& pair : pomoTodayRecord.pomodoro_records) {
+ const Pomodoro& pomo = pair.second;
+ PomodoroWidget* pomoWidget = new PomodoroWidget(pomo, pomoGroup);
+ pomoLayout->addWidget(pomoWidget);
+ }
+ pomoLayout->addStretch(1);
+ } else {
+ QLabel* noPomo = new QLabel("暂无番茄钟");
+ pomoLayout->addWidget(noPomo, 0, Qt::AlignCenter);
+ }
pomoGroup->setLayout(pomoLayout);
gridLayout->addWidget(pomoGroup, 1, 1);
@@ -799,27 +773,12 @@ void ViewLayer::initMainView()
gridLayout->setRowStretch(0, 2);
gridLayout->setRowStretch(1, 2);
gridLayout->setRowStretch(2, 1);
- gridLayout->setColumnStretch(0, 5); // 习惯框占5份
- gridLayout->setColumnStretch(1, 2); // 右侧区域占2份
+ gridLayout->setColumnStretch(0, 2);
+ gridLayout->setColumnStretch(1, 3);
// 把内容区加到主垂直布局
mainVLayout->addLayout(gridLayout, 10);
mainVLayout->addWidget(navigation_widget, 1);
-
-
- main_widget->setLayout(mainVLayout);
- dialogLabel->installEventFilter(this);
- main_widget->setStyleSheet("background: #F5F6FA;");
-
- // 初始化主界面番茄钟定时器
- if (!main_pomodoro_timer) {
- main_pomodoro_timer = new QTimer(this);
- main_pomodoro_timer->setInterval(1000); // 每秒更新
- connect(main_pomodoro_timer, &QTimer::timeout, this, &ViewLayer::updateMainPomodoroDisplay);
- }
-
- // 检查并恢复番茄钟状态(延迟执行,确保番茄钟组件已创建)
- QTimer::singleShot(200, this, &ViewLayer::checkAndRestorePomodoroState);
}
void ViewLayer::initTimelineView()
@@ -833,15 +792,18 @@ void ViewLayer::initTimelineView()
QVBoxLayout *layout = new QVBoxLayout(timeline_widget);
- // 顶部标题
+ // 顶部标题 + 返回按钮
QHBoxLayout *topLayout = new QHBoxLayout();
QLabel *title = new QLabel("时间线", timeline_widget);
QFont titleFont;
titleFont.setPointSize(18);
titleFont.setBold(true);
title->setFont(titleFont);
+ QPushButton *backButton = createButton(":/assets/images/back.png", "返回", 45, 45);
+ connect(backButton, &QPushButton::clicked, this, &ViewLayer::onBackToNavigation);
topLayout->addWidget(title);
topLayout->addStretch();
+ topLayout->addWidget(backButton);
layout->addLayout(topLayout);
// 日期选择栏
@@ -922,6 +884,7 @@ void ViewLayer::refreshTimeline()
// 向服务层请求当天记录
DateRecord raw_record = sv_Layer.getAllRecordsByDate(date);
+ std::vector events = sv_Layer.getEventsByDate(date);
// 定义用于排序合并的向量(按 Time 升序)
using TimelineItem = std::tuple