129 lines
3.8 KiB
C++
129 lines
3.8 KiB
C++
#pragma once
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <spdlog/spdlog.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "glibmm/main.h"
|
|
#include "gtkmm/mediafile.h"
|
|
#include "gtkmm/mediastream.h"
|
|
#include "sigc++/signal.h"
|
|
class TimerService {
|
|
struct TimerData {
|
|
uint64_t duration;
|
|
uint64_t timerId;
|
|
};
|
|
|
|
public:
|
|
static std::shared_ptr<TimerService> getInstance() {
|
|
if (!instance) {
|
|
instance = std::shared_ptr<TimerService>(new TimerService());
|
|
|
|
// add a timer to tick every second
|
|
Glib::signal_timeout().connect([]() {
|
|
instance->tick();
|
|
return true; // continue calling every second
|
|
},
|
|
1000);
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
void addTimer(uint64_t duration) {
|
|
this->timerAddedSignal.emit(std::to_string(duration), timerIdCounter);
|
|
|
|
this->activeTimers[timerIdCounter] = TimerData{.duration = duration, .timerId = timerIdCounter};
|
|
|
|
timerIdCounter++;
|
|
}
|
|
|
|
void expireTimer(uint64_t timerId) {
|
|
this->timerExpiredSignal.emit(timerId);
|
|
|
|
if (ringingTimerCounter == 0) {
|
|
mediaFile->set_volume(1.0);
|
|
mediaFile->set_loop(true);
|
|
mediaFile->play();
|
|
spdlog::info("Playing timer sound");
|
|
}
|
|
|
|
ringingTimerCounter++;
|
|
|
|
}
|
|
|
|
void removeTimer(uint64_t timerId) {
|
|
ringingTimerCounter--;
|
|
this->activeTimers.erase(timerId);
|
|
this->timerCancelledSignal.emit(timerId);
|
|
|
|
if (ringingTimerCounter <= 0) {
|
|
ringingTimerCounter = 0;
|
|
mediaFile->pause();
|
|
spdlog::info("Paused timer sound");
|
|
}
|
|
}
|
|
|
|
sigc::signal<void(const std::string &, u_int64_t)> &getSignalTimerSet() {
|
|
return this->timerAddedSignal;
|
|
}
|
|
|
|
sigc::signal<void(u_int64_t)> &getSignalTimerExpired() {
|
|
return this->timerExpiredSignal;
|
|
}
|
|
|
|
sigc::signal<void(u_int64_t)> &getSignalTimerCancelled() {
|
|
return this->timerCancelledSignal;
|
|
}
|
|
|
|
sigc::signal<void()> tickSignal;
|
|
|
|
private:
|
|
TimerService() {
|
|
this->mediaFile = Gtk::MediaFile::create();
|
|
if (this->mediaFile) {
|
|
this->mediaFile->set_filename("/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga");
|
|
|
|
// Connect to signals to debug playback issues
|
|
this->mediaFile->property_error().signal_changed().connect([]() {
|
|
if (auto err = mediaFile->get_error()) {
|
|
spdlog::error("Timer sound error: {}", err.what());
|
|
}
|
|
});
|
|
|
|
this->mediaFile->property_prepared().signal_changed().connect([]() {
|
|
if (mediaFile->is_prepared()) {
|
|
spdlog::info("Timer sound ready");
|
|
}
|
|
});
|
|
} else {
|
|
spdlog::error("Failed to create media file!");
|
|
}
|
|
}
|
|
|
|
inline static Glib::RefPtr<Gtk::MediaFile> mediaFile;
|
|
|
|
static inline uint64_t timerIdCounter = 0;
|
|
static inline u_int64_t ringingTimerCounter = 0;
|
|
sigc::signal<void(const std::string &, u_int64_t)> timerAddedSignal;
|
|
sigc::signal<void(u_int64_t)> timerCancelledSignal;
|
|
sigc::signal<void(u_int64_t)> timerExpiredSignal;
|
|
inline static std::shared_ptr<TimerService> instance = nullptr;
|
|
|
|
std::map<uint64_t, TimerData> activeTimers;
|
|
|
|
void tick() {
|
|
for (auto &[id, timer] : activeTimers) {
|
|
|
|
if (timer.duration > 0) {
|
|
timer.duration--;
|
|
} else if (timer.duration == 0) {
|
|
spdlog::info("Timer {} expired", timer.timerId);
|
|
expireTimer(timer.timerId);
|
|
timer.duration = -1; // Mark as expired to prevent multiple expirations
|
|
}
|
|
}
|
|
|
|
tickSignal.emit();
|
|
}
|
|
}; |