2022-04-17 15:37:04 +03:00
|
|
|
#include "mainwindow.h"
|
|
|
|
|
#include "ui_mainwindow.h"
|
|
|
|
|
#include "settingsdialog.h"
|
|
|
|
|
#include "settings.h"
|
|
|
|
|
#include "autostart.h"
|
|
|
|
|
#include "aboutdlg.h"
|
2022-04-21 13:28:50 +03:00
|
|
|
#include "config.h"
|
2022-05-07 17:02:41 +03:00
|
|
|
#include "audio_support.h"
|
2022-05-12 19:48:18 +03:00
|
|
|
#include "idle_tracking.h"
|
2022-04-17 15:37:04 +03:00
|
|
|
|
|
|
|
|
#include <QMenu>
|
|
|
|
|
#include <QAction>
|
|
|
|
|
#include <QSettings>
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QDesktopWidget>
|
|
|
|
|
#include <QSvgGenerator>
|
|
|
|
|
#include <QPalette>
|
|
|
|
|
#include <QScreen>
|
|
|
|
|
#include <QWindow>
|
|
|
|
|
#include <QFileInfo>
|
2022-05-03 21:47:32 +03:00
|
|
|
#include <QSound>
|
2022-04-17 15:37:04 +03:00
|
|
|
|
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
|
|
|
: QMainWindow(parent)
|
|
|
|
|
, ui(new Ui::MainWindow)
|
|
|
|
|
{
|
|
|
|
|
ui->setupUi(this);
|
|
|
|
|
init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MainWindow::~MainWindow()
|
|
|
|
|
{
|
|
|
|
|
if (mSettingsDialog)
|
|
|
|
|
delete mSettingsDialog;
|
|
|
|
|
delete ui;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-21 14:51:40 +03:00
|
|
|
/*static bool isDarkTheme()
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
|
|
|
|
// Thanks to stackoverflow ! Another idea is to use https://successfulsoftware.net/2021/03/31/how-to-add-a-dark-theme-to-your-qt-application/
|
|
|
|
|
auto label = QLabel("am I in the dark?");
|
|
|
|
|
auto text_hsv_value = label.palette().color(QPalette::WindowText).value();
|
|
|
|
|
auto bg_hsv_value = label.palette().color(QPalette::Background).value();
|
|
|
|
|
bool dark_theme_found = text_hsv_value > bg_hsv_value;
|
|
|
|
|
|
|
|
|
|
return dark_theme_found;
|
2022-04-21 14:51:40 +03:00
|
|
|
}*/
|
2022-04-17 15:37:04 +03:00
|
|
|
|
|
|
|
|
QIcon MainWindow::getAppIcon()
|
|
|
|
|
{
|
|
|
|
|
QIcon app_icon(QPixmap(QString(":/assets/images/coffee_cup/icon_128x128.png")));
|
|
|
|
|
|
|
|
|
|
return app_icon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QIcon MainWindow::getTrayIcon()
|
|
|
|
|
{
|
|
|
|
|
// QString app_icon_name = isDarkTheme() ? "app_icon_dark.png" : "app_icon_light.png";
|
|
|
|
|
// QIcon app_icon(QPixmap(QString(":/assets/images/%1").arg(app_icon_name)));
|
|
|
|
|
// return app_icon;
|
|
|
|
|
|
|
|
|
|
return QIcon(QPixmap(":/assets/images/coffee_cup/icon_64x64.png"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::init()
|
|
|
|
|
{
|
|
|
|
|
// Icon
|
|
|
|
|
setWindowIcon(getAppIcon());
|
|
|
|
|
|
|
|
|
|
// Tray icon
|
|
|
|
|
createTrayIcon();
|
|
|
|
|
|
|
|
|
|
// Latest config
|
|
|
|
|
loadConfig();
|
|
|
|
|
|
|
|
|
|
// Settings dialog
|
|
|
|
|
mSettingsDialog = nullptr;
|
|
|
|
|
|
2022-04-21 13:28:50 +03:00
|
|
|
// No postpone attempts yet
|
|
|
|
|
mPostponeCount = 0;
|
|
|
|
|
|
2022-05-14 22:53:13 +03:00
|
|
|
// Idle is not detected yet
|
|
|
|
|
mLastIdleMilliseconds = 0;
|
|
|
|
|
|
2022-05-12 19:48:18 +03:00
|
|
|
// Timer to start break
|
2022-11-13 20:16:09 +03:00
|
|
|
mBreakStartTimer = new QTimer(this);
|
|
|
|
|
mBreakStartTimer->setTimerType(Qt::TimerType::CoarseTimer);
|
|
|
|
|
mBreakStartTimer->setSingleShot(true);
|
2022-11-15 20:27:26 +03:00
|
|
|
connect(mBreakStartTimer, &QTimer::timeout, this, [this](){shiftTo(AppState::Break);});
|
2022-04-17 15:37:04 +03:00
|
|
|
|
2022-05-12 19:48:18 +03:00
|
|
|
// Timer to run notification about upcoming break
|
2022-11-13 20:16:09 +03:00
|
|
|
mBreakNotifyTimer = new QTimer(this);
|
|
|
|
|
mBreakNotifyTimer->setTimerType(Qt::TimerType::CoarseTimer);
|
|
|
|
|
mBreakNotifyTimer->setSingleShot(true);
|
|
|
|
|
connect(mBreakNotifyTimer, SIGNAL(timeout()), this, SLOT(onLongBreakNotify()));
|
2022-04-17 15:37:04 +03:00
|
|
|
|
2022-05-12 19:48:18 +03:00
|
|
|
// Just update UI once per minute
|
2022-04-17 15:37:04 +03:00
|
|
|
mUpdateUITimer = new QTimer(this);
|
|
|
|
|
mUpdateUITimer->setTimerType(Qt::TimerType::CoarseTimer);
|
|
|
|
|
mUpdateUITimer->setSingleShot(false);
|
2022-04-21 13:28:50 +03:00
|
|
|
mUpdateUITimer->setInterval(std::chrono::seconds(INTERVAL_UPDATE_UI));
|
2022-04-17 15:37:04 +03:00
|
|
|
connect(mUpdateUITimer, SIGNAL(timeout()), this, SLOT(onUpdateUI()));
|
|
|
|
|
mUpdateUITimer->start();
|
|
|
|
|
|
2022-05-12 19:48:18 +03:00
|
|
|
// Timer to draw progress bar during the break
|
2022-04-17 15:37:04 +03:00
|
|
|
mProgressTimer = new QTimer(this);
|
2022-04-21 13:28:50 +03:00
|
|
|
mProgressTimer->setInterval(std::chrono::milliseconds(INTERVAL_UPDATE_PROGRESS));
|
2022-04-17 15:37:04 +03:00
|
|
|
mProgressTimer->setSingleShot(false);
|
|
|
|
|
connect(mProgressTimer, SIGNAL(timeout()), this, SLOT(onProgress()));
|
|
|
|
|
|
|
|
|
|
connect(ui->mPostponeButton, SIGNAL(clicked()), this, SLOT(onLongBreakPostpone()));
|
2022-11-15 20:27:26 +03:00
|
|
|
connect(ui->mSkipButton, &QPushButton::clicked, this, [this](){shiftTo(AppState::Counting);});
|
2022-04-17 15:37:04 +03:00
|
|
|
|
|
|
|
|
// Use the latest config
|
|
|
|
|
applyConfig();
|
|
|
|
|
|
2022-11-13 20:16:09 +03:00
|
|
|
shiftTo(AppState::Counting);
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::loadConfig()
|
|
|
|
|
{
|
|
|
|
|
app_settings settings;
|
|
|
|
|
mAppConfig = settings.load();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::applyConfig()
|
|
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
if (mBreakStartTimer)
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
if (mBreakStartTimer->interval() != mAppConfig.longbreak_interval)
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
mBreakStartTimer->stop();
|
|
|
|
|
mBreakStartTimer->setInterval(std::chrono::seconds(mAppConfig.longbreak_interval));
|
|
|
|
|
mBreakStartTimer->start();
|
2022-04-17 15:37:04 +03:00
|
|
|
|
2022-11-13 20:16:09 +03:00
|
|
|
mBreakNotifyTimer->stop();
|
|
|
|
|
mBreakNotifyTimer->setInterval(std::chrono::seconds(mAppConfig.longbreak_interval - 30));
|
|
|
|
|
mBreakNotifyTimer->start();
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mAppConfig.window_on_top)
|
|
|
|
|
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
|
|
|
|
else
|
|
|
|
|
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
|
|
|
|
|
|
|
|
|
if (mAppConfig.autostart)
|
|
|
|
|
{
|
2022-04-18 10:27:23 +03:00
|
|
|
auto path_to_me = QFileInfo(QApplication::arguments().front()).absoluteFilePath();
|
2022-04-17 15:37:04 +03:00
|
|
|
autostart::enable(path_to_me.toStdString());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
autostart::disable();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::schedule()
|
|
|
|
|
{
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::test_1()
|
|
|
|
|
{
|
|
|
|
|
// 10 seconds test break
|
|
|
|
|
mAppConfig.longbreak_length = 10;
|
|
|
|
|
mAppConfig.longbreak_postpone_interval = 10;
|
|
|
|
|
mAppConfig.longbreak_interval = 10;
|
|
|
|
|
|
|
|
|
|
mAppConfig.window_on_top = true;
|
|
|
|
|
mAppConfig.verbose = true;
|
2022-04-21 13:28:50 +03:00
|
|
|
applyConfig();
|
|
|
|
|
onUpdateUI();
|
2022-11-13 20:53:35 +03:00
|
|
|
shiftTo(AppState::Break);
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::test_2()
|
|
|
|
|
{
|
|
|
|
|
// 60 seconds test break
|
|
|
|
|
mAppConfig.longbreak_length = 60;
|
|
|
|
|
mAppConfig.longbreak_postpone_interval = 60;
|
2022-05-03 21:47:32 +03:00
|
|
|
mAppConfig.longbreak_interval = 60;
|
2022-04-17 15:37:04 +03:00
|
|
|
|
|
|
|
|
mAppConfig.window_on_top = true;
|
|
|
|
|
mAppConfig.verbose = true;
|
|
|
|
|
|
|
|
|
|
applyConfig();
|
2022-04-21 13:28:50 +03:00
|
|
|
onUpdateUI();
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::showMe()
|
|
|
|
|
{
|
2022-04-20 18:18:44 +03:00
|
|
|
QScreen* screen = nullptr;
|
|
|
|
|
if (mAppConfig.preferred_monitor == Primary_Monitor)
|
|
|
|
|
screen = QGuiApplication::primaryScreen();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto screen_list = QGuiApplication::screens();
|
|
|
|
|
auto screen_iter = std::find_if(screen_list.begin(), screen_list.end(), [this](QScreen* s){return s->name() == mAppConfig.preferred_monitor;});
|
|
|
|
|
if (screen_iter != screen_list.end())
|
|
|
|
|
screen = *screen_iter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (screen)
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
2022-04-20 18:18:44 +03:00
|
|
|
show();
|
|
|
|
|
if (windowHandle())
|
|
|
|
|
{
|
|
|
|
|
windowHandle()->setScreen(screen);
|
|
|
|
|
setGeometry(screen->geometry());
|
2022-05-25 11:58:12 +03:00
|
|
|
// qDebug() << "Window moved to screen " << screen->name() + " / " + screen->model() + " " + screen->manufacturer();
|
2022-04-20 18:18:44 +03:00
|
|
|
}
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
2022-11-13 20:16:09 +03:00
|
|
|
|
|
|
|
|
#if !defined(DEBUG)
|
2022-04-20 18:18:44 +03:00
|
|
|
showFullScreen();
|
2022-11-13 20:16:09 +03:00
|
|
|
#endif
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::hideMe()
|
|
|
|
|
{
|
|
|
|
|
this->hide();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString secondsToText(int seconds)
|
|
|
|
|
{
|
|
|
|
|
if (seconds < 60)
|
2022-04-21 13:28:50 +03:00
|
|
|
return QObject::tr("%1 seconds").arg(seconds);
|
2022-04-17 15:37:04 +03:00
|
|
|
else
|
2022-04-21 13:28:50 +03:00
|
|
|
return QObject::tr("%1 minutes").arg(seconds / 60);
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::createTrayIcon()
|
|
|
|
|
{
|
|
|
|
|
mTrayIcon = new QSystemTrayIcon(this);
|
|
|
|
|
QMenu* menu = new QMenu(this);
|
|
|
|
|
|
|
|
|
|
QAction* nextBreakAction = new QAction(tr("Start next break"), menu);
|
|
|
|
|
connect(nextBreakAction, SIGNAL(triggered()), this, SLOT(onNextBreak()));
|
|
|
|
|
|
|
|
|
|
QAction* settingsAction = new QAction(tr("Settings"), menu);
|
|
|
|
|
connect(settingsAction, SIGNAL(triggered()), this, SLOT(onSettings()));
|
|
|
|
|
|
|
|
|
|
QAction* aboutAction = new QAction(tr("About"), menu);
|
|
|
|
|
connect(aboutAction, SIGNAL(triggered()), this, SLOT(onAbout()));
|
|
|
|
|
|
|
|
|
|
QAction* exitAction = new QAction(tr("Exit"), menu);
|
|
|
|
|
connect(exitAction, SIGNAL(triggered()), this, SLOT(onExit()));
|
|
|
|
|
|
|
|
|
|
menu->addAction(nextBreakAction);
|
|
|
|
|
menu->addAction(settingsAction);
|
|
|
|
|
menu->addAction(aboutAction);
|
|
|
|
|
menu->addAction(exitAction);
|
|
|
|
|
|
|
|
|
|
mTrayIcon->setContextMenu(menu);
|
|
|
|
|
mTrayIcon->setIcon(getTrayIcon());
|
|
|
|
|
mTrayIcon->setToolTip(AppName);
|
|
|
|
|
mTrayIcon->show();
|
2022-05-21 15:27:42 +03:00
|
|
|
connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
|
|
|
|
this, SLOT(onTrayIconActivated(QSystemTrayIcon::ActivationReason)));
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
2022-05-20 17:59:26 +03:00
|
|
|
static int msec2min(int msec)
|
|
|
|
|
{
|
|
|
|
|
float min_f = float(msec) / 1000 / 60;
|
|
|
|
|
return (int)(min_f + 0.5f);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-15 20:27:26 +03:00
|
|
|
QString state2str(AppState state)
|
|
|
|
|
{
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case AppState::None:
|
|
|
|
|
return "None";
|
|
|
|
|
case AppState::Break:
|
|
|
|
|
return "Break";
|
|
|
|
|
case AppState::Idle:
|
|
|
|
|
return "Idle";
|
|
|
|
|
case AppState::Counting:
|
|
|
|
|
return "Counting";
|
|
|
|
|
}
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-13 20:16:09 +03:00
|
|
|
void MainWindow::shiftTo(AppState newState)
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
if (newState == mState)
|
|
|
|
|
return;
|
2022-11-15 20:27:26 +03:00
|
|
|
#if defined(DEBUG)
|
|
|
|
|
qDebug() << state2str(mState) << " -> " << state2str(newState);
|
|
|
|
|
#endif
|
2022-11-13 20:16:09 +03:00
|
|
|
|
|
|
|
|
switch (newState)
|
2022-05-14 22:53:13 +03:00
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
case AppState::None:
|
|
|
|
|
// Do nothing, app is not started
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case AppState::Idle:
|
|
|
|
|
onIdleStart();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case AppState::Break:
|
|
|
|
|
// Break is active
|
|
|
|
|
onLongBreakStart();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case AppState::Counting:
|
|
|
|
|
// Working, break is closing
|
|
|
|
|
if (mState == AppState::Break)
|
|
|
|
|
onLongBreakEnd();
|
|
|
|
|
else
|
|
|
|
|
if (mState == AppState::Idle)
|
|
|
|
|
onIdleEnd();
|
|
|
|
|
break;
|
2022-05-14 22:53:13 +03:00
|
|
|
}
|
|
|
|
|
|
2022-11-13 20:16:09 +03:00
|
|
|
mState = newState;
|
|
|
|
|
onUpdateUI();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onUpdateUI()
|
|
|
|
|
{
|
|
|
|
|
int idle_milliseconds = 0;
|
|
|
|
|
switch (mState)
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
case AppState::None:
|
|
|
|
|
// Do nothing, app is not started
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case AppState::Idle:
|
|
|
|
|
// Detected idle, don't count this time as working
|
|
|
|
|
// But check - maybe idle is over
|
|
|
|
|
idle_milliseconds = get_idle_time_dynamically();
|
|
|
|
|
if (idle_milliseconds < mAppConfig.idle_timeout * 60 * 1000)
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
shiftTo(AppState::Counting);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case AppState::Break:
|
|
|
|
|
// Break is active
|
|
|
|
|
if (mTrayIcon)
|
2022-04-17 15:37:04 +03:00
|
|
|
mTrayIcon->setToolTip(QString());
|
2022-11-13 20:16:09 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case AppState::Counting:
|
|
|
|
|
// Working, break is closing
|
|
|
|
|
// Check maybe it is idle ?
|
|
|
|
|
if (!mIdleStart && mAppConfig.idle_timeout)
|
|
|
|
|
{
|
|
|
|
|
idle_milliseconds = get_idle_time_dynamically();
|
|
|
|
|
if (idle_milliseconds >= mAppConfig.idle_timeout * 60 * 1000)
|
|
|
|
|
{
|
|
|
|
|
shiftTo(AppState::Idle);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
2022-11-13 20:16:09 +03:00
|
|
|
|
|
|
|
|
// Update tray icon
|
|
|
|
|
if (mTrayIcon)
|
2022-04-17 15:37:04 +03:00
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
auto remaining_milliseconds = mBreakStartTimer->remainingTime();
|
2022-05-20 17:59:26 +03:00
|
|
|
if (remaining_milliseconds < 60000)
|
2022-04-17 15:37:04 +03:00
|
|
|
mTrayIcon->setToolTip(tr("Less than a minute left until the next break."));
|
|
|
|
|
else
|
2022-05-20 17:59:26 +03:00
|
|
|
mTrayIcon->setToolTip(tr("There are %1 minutes left until the next break.").arg(msec2min(remaining_milliseconds)));
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
2022-11-13 20:16:09 +03:00
|
|
|
|
|
|
|
|
break;
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
2022-04-21 13:28:50 +03:00
|
|
|
|
|
|
|
|
ui->mSkipButton->setVisible(mPostponeCount > 0);
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onLongBreakNotify()
|
|
|
|
|
{
|
|
|
|
|
mTrayIcon->showMessage(tr("New break"),
|
|
|
|
|
tr("New break will start in %1 secs").arg(Default_Notify_Length),
|
|
|
|
|
getAppIcon(),
|
2022-04-21 13:28:50 +03:00
|
|
|
INTERVAL_NOTIFICATION);
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onLongBreakStart()
|
|
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
mBreakStartTimer->stop();
|
|
|
|
|
mBreakNotifyTimer->stop();
|
2022-11-18 21:48:55 +03:00
|
|
|
qDebug() << "Stop main and notify timers.";
|
2022-05-29 16:59:56 +03:00
|
|
|
|
2022-05-14 22:53:13 +03:00
|
|
|
// Reset idle counter
|
2022-11-13 20:16:09 +03:00
|
|
|
mIdleStart.reset();
|
2022-05-29 16:59:56 +03:00
|
|
|
|
2022-11-13 20:16:09 +03:00
|
|
|
// Show the button "Postpone"
|
2022-04-17 15:37:04 +03:00
|
|
|
ui->mPostponeButton->setText(tr("Postpone for ") + secondsToText(mAppConfig.longbreak_postpone_interval));
|
2022-11-13 20:16:09 +03:00
|
|
|
|
|
|
|
|
// Show the screen
|
2022-04-17 15:37:04 +03:00
|
|
|
showMe();
|
|
|
|
|
|
2022-11-13 20:16:09 +03:00
|
|
|
// Save start time
|
2022-04-17 15:37:04 +03:00
|
|
|
mBreakStartTime = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
|
|
// Start progress bar
|
|
|
|
|
mProgressTimer->start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onLongBreakEnd()
|
|
|
|
|
{
|
2022-05-25 11:58:12 +03:00
|
|
|
// qDebug() << "Long break ends.";
|
2022-04-17 15:37:04 +03:00
|
|
|
|
2022-04-21 13:28:50 +03:00
|
|
|
// Reset postpone counter
|
|
|
|
|
mPostponeCount = 0;
|
|
|
|
|
|
2022-04-17 15:37:04 +03:00
|
|
|
// Prepare to next triggering
|
|
|
|
|
ui->mProgressBar->setValue(0);
|
|
|
|
|
|
|
|
|
|
// Hide the window
|
|
|
|
|
hideMe();
|
|
|
|
|
|
2022-04-21 14:51:40 +03:00
|
|
|
mProgressTimer->stop();
|
|
|
|
|
|
2022-04-17 15:37:04 +03:00
|
|
|
// Start new timer
|
2022-11-15 20:27:26 +03:00
|
|
|
if (!mBreakStartTimer->isActive())
|
2022-11-18 21:48:55 +03:00
|
|
|
{
|
2022-11-15 20:27:26 +03:00
|
|
|
mBreakStartTimer->start(std::chrono::seconds(mAppConfig.longbreak_interval));
|
2022-11-18 21:48:55 +03:00
|
|
|
qDebug() << "Start main timer for " << mAppConfig.longbreak_interval << " seconds.";
|
|
|
|
|
}
|
2022-11-15 20:27:26 +03:00
|
|
|
if (!mBreakNotifyTimer->isActive())
|
2022-11-18 21:48:55 +03:00
|
|
|
{
|
2022-11-15 20:27:26 +03:00
|
|
|
mBreakNotifyTimer->start(std::chrono::seconds(mAppConfig.longbreak_interval - 30));
|
2022-11-18 21:48:55 +03:00
|
|
|
qDebug() << "Start notify timer for " << mAppConfig.longbreak_interval - 30 << " seconds.";
|
|
|
|
|
}
|
2022-04-17 15:37:04 +03:00
|
|
|
|
2022-11-15 20:27:26 +03:00
|
|
|
// Play selected audio. When break is postponed - audio is not played
|
|
|
|
|
if (!mPostponeCount)
|
|
|
|
|
play_audio(mAppConfig.play_audio);
|
2022-05-03 21:47:32 +03:00
|
|
|
|
|
|
|
|
// Run script
|
|
|
|
|
if (!mAppConfig.script_on_break_finish.isEmpty())
|
|
|
|
|
{
|
|
|
|
|
int retcode = system(mAppConfig.script_on_break_finish.toStdString().c_str());
|
|
|
|
|
if (retcode != 0)
|
|
|
|
|
qDebug() << "User script exited with error code " << retcode;
|
|
|
|
|
}
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onLongBreakPostpone()
|
|
|
|
|
{
|
2022-05-25 11:58:12 +03:00
|
|
|
// qDebug() << "Long break postponed.";
|
2022-04-21 13:28:50 +03:00
|
|
|
mPostponeCount++;
|
|
|
|
|
|
2022-04-17 15:37:04 +03:00
|
|
|
hideMe();
|
|
|
|
|
|
|
|
|
|
mProgressTimer->stop();
|
|
|
|
|
ui->mProgressBar->setValue(0);
|
|
|
|
|
|
|
|
|
|
// Start timer again
|
2022-11-13 20:16:09 +03:00
|
|
|
mBreakStartTimer->stop();
|
|
|
|
|
mBreakStartTimer->start(std::chrono::seconds(mAppConfig.longbreak_postpone_interval));
|
|
|
|
|
mBreakNotifyTimer->stop();
|
|
|
|
|
mBreakNotifyTimer->start(std::chrono::seconds(mAppConfig.longbreak_postpone_interval - 30));
|
2022-04-17 15:37:04 +03:00
|
|
|
|
2022-11-15 20:27:26 +03:00
|
|
|
shiftTo(AppState::Counting);
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onProgress()
|
|
|
|
|
{
|
|
|
|
|
auto timestamp = std::chrono::steady_clock::now();
|
|
|
|
|
auto delta = std::chrono::duration_cast<std::chrono::seconds>(timestamp - mBreakStartTime).count();
|
|
|
|
|
|
|
|
|
|
int percents = (delta / float(mAppConfig.longbreak_length) * 100);
|
|
|
|
|
ui->mProgressBar->setValue(percents);
|
|
|
|
|
int remaining = mAppConfig.longbreak_length - delta;
|
|
|
|
|
if (remaining < 0)
|
|
|
|
|
remaining = 0;
|
|
|
|
|
|
|
|
|
|
ui->mRemainingLabel->setText(QString("Remaining: ") + secondsToText(remaining));
|
|
|
|
|
|
|
|
|
|
if (percents > 100)
|
|
|
|
|
{
|
|
|
|
|
mProgressTimer->stop();
|
2022-11-13 20:16:09 +03:00
|
|
|
shiftTo(AppState::Counting);
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
showMe();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onNextBreak()
|
|
|
|
|
{
|
2022-11-13 20:16:09 +03:00
|
|
|
shiftTo(AppState::Break);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onIdleStart()
|
|
|
|
|
{
|
|
|
|
|
if (mState != AppState::Counting)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Detected idle
|
|
|
|
|
// Timestamp when idle started
|
|
|
|
|
mIdleStart = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
|
|
// How much working time remains
|
2022-11-18 21:48:55 +03:00
|
|
|
mRemainingWorkInterval = mBreakStartTimer->remainingTime() / 1000;
|
2022-11-13 20:16:09 +03:00
|
|
|
|
|
|
|
|
// Stop main & notify timers
|
|
|
|
|
mBreakStartTimer->stop();
|
|
|
|
|
mBreakNotifyTimer->stop();
|
2022-11-18 21:48:55 +03:00
|
|
|
qDebug() << "Stop main and notify timers.";
|
2022-11-13 20:16:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onIdleEnd()
|
|
|
|
|
{
|
|
|
|
|
if (mState != AppState::Idle)
|
|
|
|
|
return;
|
|
|
|
|
|
2022-05-29 16:59:56 +03:00
|
|
|
mIdleStart.reset();
|
|
|
|
|
|
2022-11-13 20:16:09 +03:00
|
|
|
// Update timer(s) duration
|
2022-11-18 21:48:55 +03:00
|
|
|
if (mRemainingWorkInterval)
|
2022-11-13 20:53:35 +03:00
|
|
|
{
|
2022-11-18 21:48:55 +03:00
|
|
|
mBreakStartTimer->setInterval(std::chrono::seconds(*mRemainingWorkInterval));
|
|
|
|
|
if (mRemainingWorkInterval > INTERVAL_NOTIFICATION)
|
|
|
|
|
mBreakNotifyTimer->setInterval(std::chrono::seconds(*mRemainingWorkInterval - INTERVAL_NOTIFICATION));
|
|
|
|
|
mRemainingWorkInterval.reset();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mBreakStartTimer->setInterval(std::chrono::seconds(mAppConfig.longbreak_interval));
|
|
|
|
|
if (mRemainingWorkInterval > INTERVAL_NOTIFICATION)
|
|
|
|
|
mBreakNotifyTimer->setInterval(std::chrono::seconds(mAppConfig.longbreak_interval - INTERVAL_NOTIFICATION));
|
2022-11-13 20:53:35 +03:00
|
|
|
}
|
2022-04-17 15:37:04 +03:00
|
|
|
|
2022-11-18 21:48:55 +03:00
|
|
|
if (!mBreakStartTimer->isActive())
|
|
|
|
|
mBreakStartTimer->start();
|
|
|
|
|
if (!mBreakNotifyTimer->isActive())
|
|
|
|
|
mBreakNotifyTimer->start();
|
2022-04-17 15:37:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onSettings()
|
|
|
|
|
{
|
|
|
|
|
if (mSettingsDialog == nullptr)
|
|
|
|
|
{
|
|
|
|
|
// Settings dialog must be top level window to be positioned on the primary screen
|
|
|
|
|
mSettingsDialog = new SettingsDialog(nullptr);
|
|
|
|
|
connect(mSettingsDialog, &QDialog::accepted, [this]()
|
|
|
|
|
{
|
|
|
|
|
mAppConfig = app_settings::load();
|
|
|
|
|
applyConfig();
|
|
|
|
|
mSettingsDialog->hide();
|
2022-04-21 13:28:50 +03:00
|
|
|
onUpdateUI();
|
2022-04-17 15:37:04 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
connect(mSettingsDialog, &QDialog::rejected, [this]()
|
|
|
|
|
{
|
|
|
|
|
mSettingsDialog->hide();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
// Move to primary screen
|
|
|
|
|
mSettingsDialog->show();
|
|
|
|
|
QScreen* screen = QGuiApplication::primaryScreen();
|
|
|
|
|
mSettingsDialog->windowHandle()->setScreen(screen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onAbout()
|
|
|
|
|
{
|
|
|
|
|
AboutDlg dlg;
|
|
|
|
|
dlg.exec();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::onExit()
|
|
|
|
|
{
|
|
|
|
|
this->close();
|
|
|
|
|
QApplication::exit();
|
|
|
|
|
}
|
2022-05-21 15:27:42 +03:00
|
|
|
|
|
|
|
|
void MainWindow::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
|
|
|
|
{
|
|
|
|
|
switch(reason)
|
|
|
|
|
{
|
|
|
|
|
// Show context menu on single click
|
|
|
|
|
case QSystemTrayIcon::Trigger:
|
|
|
|
|
mTrayIcon->contextMenu()->popup(QCursor::pos());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case QSystemTrayIcon::Unknown:
|
|
|
|
|
case QSystemTrayIcon::Context:
|
|
|
|
|
case QSystemTrayIcon::DoubleClick:
|
|
|
|
|
case QSystemTrayIcon::MiddleClick:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|