diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32db237..7a99eff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -105,6 +105,9 @@ target_sources(tomato PUBLIC ./tox_friend_faux_offline_messaging.hpp ./tox_friend_faux_offline_messaging.cpp + ./status_indicator.hpp + ./status_indicator.cpp + ./chat_gui4.hpp ./chat_gui4.cpp diff --git a/src/main_screen.cpp b/src/main_screen.cpp index 8da67ca..63539a6 100644 --- a/src/main_screen.cpp +++ b/src/main_screen.cpp @@ -43,6 +43,7 @@ MainScreen::MainScreen(SimpleConfigModel&& conf_, SDL_Renderer* renderer_, Theme contact_tc(tal, sdlrtu), mil(), msg_tc(mil, sdlrtu), + si(rmm, cr, SDL_GetRenderWindow(renderer_)), cg(conf, os, rmm, cr, sdlrtu, contact_tc, msg_tc, theme), sw(conf), osui(os), diff --git a/src/main_screen.hpp b/src/main_screen.hpp index 59d3b7a..ae3b005 100644 --- a/src/main_screen.hpp +++ b/src/main_screen.hpp @@ -29,6 +29,7 @@ #include "./tox_avatar_loader.hpp" #include "./message_image_loader.hpp" +#include "./status_indicator.hpp" #include "./chat_gui4.hpp" #include "./chat_gui/settings_window.hpp" #include "./object_store_ui.hpp" @@ -91,6 +92,7 @@ struct MainScreen final : public Screen { MessageImageLoader mil; TextureCache msg_tc; + StatusIndicator si; ChatGui4 cg; SettingsWindow sw; ObjectStoreUI osui; diff --git a/src/status_indicator.cpp b/src/status_indicator.cpp new file mode 100644 index 0000000..ab37bb9 --- /dev/null +++ b/src/status_indicator.cpp @@ -0,0 +1,69 @@ +#include "./status_indicator.hpp" + +#include +#include + +#include "./icon_generator.hpp" + +#include + +void StatusIndicator::updateState(State state) { + if (_state == state) { + return; + } + + _state = state; + + std::unique_ptr surf{nullptr, &SDL_DestroySurface}; + + switch (state) { + case State::base: + surf = {IconGenerator::base(), &SDL_DestroySurface}; + break; + case State::unread: + surf = {IconGenerator::colorIndicator(1.f, .5f, 0.f, 1.f), &SDL_DestroySurface}; + break; + case State::none: + break; + } + + SDL_SetWindowIcon(_main_window, surf.get()); +} + +StatusIndicator::StatusIndicator( + RegistryMessageModelI& rmm, + Contact3Registry& cr, + SDL_Window* main_window +) : + _rmm(rmm), + _cr(cr), + _main_window(main_window) +{ + // start off with base icon + updateState(State::base); +} + +void StatusIndicator::render(float delta) { + _cooldown -= delta; + if (_cooldown <= 0.f) { + _cooldown = 1.f; // once a second + + bool has_unread = false; + for (const auto& c : _cr.view()) { + // maybe cache mm? + if (const auto* mm = _rmm.get(c); mm != nullptr) { + if (const auto* unread_storage = mm->storage(); unread_storage != nullptr && !unread_storage->empty()) { + has_unread = true; + break; + } + } + } + + if (has_unread) { + updateState(State::unread); + } else { + updateState(State::base); + } + } +} + diff --git a/src/status_indicator.hpp b/src/status_indicator.hpp new file mode 100644 index 0000000..29e852f --- /dev/null +++ b/src/status_indicator.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include + +// service that sets window and tray icon depending on program state + +class StatusIndicator { + RegistryMessageModelI& _rmm; + Contact3Registry& _cr; + + SDL_Window* _main_window; + // systray ptr here + + float _cooldown {1.f}; + + enum class State { + base, + unread, + none, // only used for initialization + } _state = State::none; + + void updateState(State state); + + public: + StatusIndicator( + RegistryMessageModelI& rmm, + Contact3Registry& cr, + SDL_Window* main_window + ); + + // does not actually render, just on the render thread + void render(float delta); +}; +