diff --git a/include/components/timer.hpp b/include/components/timer.hpp index 7aa4d81..2f95cb7 100644 --- a/include/components/timer.hpp +++ b/include/components/timer.hpp @@ -67,7 +67,7 @@ class Timer : public Gtk::Box { } void activateTimer() { - std::cout << "Timer activated" << std::endl; + // std::cout << "Timer activated" << std::endl; } void updateTimeLeft(uint64_t timeValue) { diff --git a/include/helpers/string.hpp b/include/helpers/string.hpp index 7908618..1f160d9 100644 --- a/include/helpers/string.hpp +++ b/include/helpers/string.hpp @@ -41,6 +41,12 @@ class StringHelper { if (input.length() <= maxSize) { return input; } - return input.substr(0, maxSize) + "..."; + + size_t len = maxSize; + while (len > 0 && (static_cast(input[len]) & 0xC0) == 0x80) { + len--; + } + + return input.substr(0, len) + "..."; } }; \ No newline at end of file diff --git a/include/services/timerService.hpp b/include/services/timerService.hpp index abdbf1a..5c86102 100644 --- a/include/services/timerService.hpp +++ b/include/services/timerService.hpp @@ -2,9 +2,12 @@ #include #include +#include #include #include "glibmm/main.h" +#include "gtkmm/mediafile.h" +#include "gtkmm/mediastream.h" #include "sigc++/signal.h" class TimerService { struct TimerData { @@ -15,7 +18,7 @@ class TimerService { public: static std::shared_ptr getInstance() { if (!instance) { - instance = std::make_shared(); + instance = std::shared_ptr(new TimerService()); // add a timer to tick every second Glib::signal_timeout().connect([]() { @@ -37,11 +40,28 @@ class TimerService { 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 &getSignalTimerSet() { @@ -59,7 +79,32 @@ class TimerService { sigc::signal tickSignal; private: - static inline uint64_t timerIdCounter = 0; + 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 mediaFile; + + static inline uint64_t timerIdCounter = 0; + static inline u_int64_t ringingTimerCounter = 0; sigc::signal timerAddedSignal; sigc::signal timerCancelledSignal; sigc::signal timerExpiredSignal; @@ -73,6 +118,7 @@ class TimerService { 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 } diff --git a/include/widgets/notification/baseNotification.hpp b/include/widgets/notification/baseNotification.hpp index 286fb39..069ba17 100644 --- a/include/widgets/notification/baseNotification.hpp +++ b/include/widgets/notification/baseNotification.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "gdkmm/monitor.h" @@ -9,7 +10,7 @@ #define DEFAULT_NOTIFICATION_TIMEOUT 6700 -class BaseNotification : public Gtk::Window { +class BaseNotification : public Gtk::Window, public std::enable_shared_from_this { public: BaseNotification(uint64_t notificationId, std::shared_ptr monitor); diff --git a/src/widgets/notification/baseNotification.cpp b/src/widgets/notification/baseNotification.cpp index 48d8f2b..c05fb03 100644 --- a/src/widgets/notification/baseNotification.cpp +++ b/src/widgets/notification/baseNotification.cpp @@ -81,8 +81,8 @@ void BaseNotification::start_auto_close_timeout(int timeoutMs) { } autoCloseDeadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeoutMs); - autoCloseConnection = Glib::signal_timeout().connect([this]() { - this->getSignalClose().emit(this->notificationId); + autoCloseConnection = Glib::signal_timeout().connect([self = shared_from_this()]() { + self->getSignalClose().emit(self->getNotificationId()); return false; // Don't repeat }, timeoutMs); diff --git a/src/widgets/notification/notificationWindow.cpp b/src/widgets/notification/notificationWindow.cpp index 463d4c1..e518e13 100644 --- a/src/widgets/notification/notificationWindow.cpp +++ b/src/widgets/notification/notificationWindow.cpp @@ -44,23 +44,29 @@ NotificationWindow::NotificationWindow(uint64_t notificationId, std::shared_ptr< header_box->append(*img); } - auto app_label = Gtk::make_managed(StringHelper::trimToSize(notify.app_name, 24)); + auto app_label = Gtk::make_managed(notify.app_name); app_label->set_halign(Gtk::Align::START); + app_label->set_ellipsize(Pango::EllipsizeMode::END); + app_label->set_max_width_chars(24); app_label->set_wrap(false); app_label->add_css_class("notification-app-name"); header_box->append(*app_label); vbox->append(*header_box); // Summary label - auto summary_label = Gtk::make_managed("" + StringHelper::trimToSize(notify.summary, 20) + ""); + auto summary_label = Gtk::make_managed("" + notify.summary + ""); summary_label->set_use_markup(true); summary_label->set_halign(Gtk::Align::START); + summary_label->set_ellipsize(Pango::EllipsizeMode::END); + summary_label->set_lines(1); summary_label->set_wrap(true); vbox->append(*summary_label); - auto body_label = Gtk::make_managed(StringHelper::trimToSize(notify.body, 100)); + auto body_label = Gtk::make_managed(notify.body); body_label->set_use_markup(true); body_label->set_halign(Gtk::Align::START); + body_label->set_ellipsize(Pango::EllipsizeMode::END); + body_label->set_lines(3); body_label->set_wrap(true); vbox->append(*body_label); diff --git a/src/widgets/notification/spotifyNotification.cpp b/src/widgets/notification/spotifyNotification.cpp index 78e3f3c..79d9867 100644 --- a/src/widgets/notification/spotifyNotification.cpp +++ b/src/widgets/notification/spotifyNotification.cpp @@ -36,10 +36,12 @@ SpotifyNotification::SpotifyNotification(uint64_t notificationId, std::shared_pt auto artistLabel = Gtk::make_managed(); if (!mpris.artist.empty()) { - artistLabel->set_text(StringHelper::trimToSize(mpris.artist[0], 30)); + artistLabel->set_text(mpris.artist[0]); } else { artistLabel->set_text("Unknown Artist"); } + artistLabel->set_ellipsize(Pango::EllipsizeMode::END); + artistLabel->set_max_width_chars(30); artistLabel->set_hexpand(true); artistLabel->set_halign(Gtk::Align::CENTER);