From 54c89104de0fca8d2e1df411bfb53d5c09a5fc5e Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 30 Apr 2025 14:47:35 +0200 Subject: [PATCH] DonationNag: ask after each major update (#10213) This changes how the donation nag timing works. The donation nag will now appear: - after a major update (e.g. 48 -> 49)* - once in late july - once in december however, a donation nag will never pop up more than once a month. So, if there is an update on the 26th of November, and you get a popup on the 28th, you will not get one in december. This is of course still disableable in your config. --- src/managers/DonationNagManager.cpp | 92 +++++++++++++++++++++-------- src/managers/DonationNagManager.hpp | 11 +++- 2 files changed, 78 insertions(+), 25 deletions(-) diff --git a/src/managers/DonationNagManager.cpp b/src/managers/DonationNagManager.cpp index d7eab9ae..454a02a0 100644 --- a/src/managers/DonationNagManager.cpp +++ b/src/managers/DonationNagManager.cpp @@ -10,7 +10,9 @@ #include "../helpers/fs/FsUtils.hpp" #include +#include using namespace Hyprutils::OS; +using namespace Hyprutils::String; constexpr const char* LAST_NAG_FILE_NAME = "lastNag"; constexpr uint64_t DAY_IN_SECONDS = 3600ULL * 24; @@ -46,29 +48,28 @@ CDonationNagManager::CDonationNagManager() { const auto EPOCH = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - const auto LASTNAGSTR = NFsUtils::readFileAsString(*DATAROOT + "/" + LAST_NAG_FILE_NAME); - - if (!LASTNAGSTR) { - const auto EPOCHSTR = std::format("{}", EPOCH); - NFsUtils::writeToFile(*DATAROOT + "/" + LAST_NAG_FILE_NAME, EPOCHSTR); + uint64_t currentMajor = 0; + try { + CVarList vl(HYPRLAND_VERSION, 0, '.'); + currentMajor = std::stoull(vl[1]); + } catch (...) { + // ???? return; } - uint64_t LAST_EPOCH = 0; + auto state = getState(); - try { - LAST_EPOCH = std::stoull(*LASTNAGSTR); - } catch (std::exception& e) { - Debug::log(ERR, "DonationNag: Last epoch invalid? Failed to parse \"{}\". Setting to today.", *LASTNAGSTR); - const auto EPOCHSTR = std::format("{}", EPOCH); - NFsUtils::writeToFile(*DATAROOT + "/" + LAST_NAG_FILE_NAME, EPOCHSTR); + if ((!state.major && currentMajor <= 48) || !state.epoch) { + state.major = currentMajor; + state.epoch = state.epoch == 0 ? EPOCH : state.epoch; + writeState(state); return; } // don't nag if the last nag was less than a month ago. This is // mostly for first-time nags, as other nags happen in specific time frames shorter than a month - if (EPOCH - LAST_EPOCH < MONTH_IN_SECONDS) { - Debug::log(LOG, "DonationNag: last nag was {} days ago, too early for a nag.", (int)std::round((EPOCH - LAST_EPOCH) / (double)MONTH_IN_SECONDS)); + if (EPOCH - state.epoch < MONTH_IN_SECONDS) { + Debug::log(LOG, "DonationNag: last nag was {} days ago, too early for a nag.", (int)std::round((EPOCH - state.epoch) / (double)DAY_IN_SECONDS)); return; } @@ -92,23 +93,66 @@ CDonationNagManager::CDonationNagManager() { Debug::log(LOG, "DonationNag: hit nag month {} days {}-{}, it's {} today, nagging", MONTH, nagPoint.dayStart, nagPoint.dayEnd, DAY); - m_bFired = true; + fire(); - const auto EPOCHSTR = std::format("{}", EPOCH); - NFsUtils::writeToFile(*DATAROOT + "/" + LAST_NAG_FILE_NAME, EPOCHSTR); - - g_pEventLoopManager->doLater([] { - CProcess proc("hyprland-donate-screen", {}); - proc.runAsync(); - }); + state.major = currentMajor; + state.epoch = EPOCH; + writeState(state); break; } if (!m_bFired) - Debug::log(LOG, "DonationNag: didn't hit any nagging periods"); + Debug::log(LOG, "DonationNag: didn't hit any nagging periods, checking update"); + + if (state.major < currentMajor) { + Debug::log(LOG, "DonationNag: hit nag for major update {} -> {}", state.major, currentMajor); + + fire(); + + state.major = currentMajor; + state.epoch = EPOCH; + writeState(state); + } + + if (!m_bFired) + Debug::log(LOG, "DonationNag: didn't hit nagging conditions"); } bool CDonationNagManager::fired() { return m_bFired; -} \ No newline at end of file +} + +void CDonationNagManager::fire() { + static const auto DATAROOT = NFsUtils::getDataHome(); + + m_bFired = true; + + g_pEventLoopManager->doLater([] { + CProcess proc("hyprland-donate-screen", {}); + proc.runAsync(); + }); +} + +CDonationNagManager::SStateData CDonationNagManager::getState() { + static const auto DATAROOT = NFsUtils::getDataHome(); + const auto STR = NFsUtils::readFileAsString(*DATAROOT + "/" + LAST_NAG_FILE_NAME); + + if (!STR.has_value()) + return {}; + + CVarList lines(*STR, 0, '\n'); + CDonationNagManager::SStateData state; + + try { + state.epoch = std::stoull(lines[0]); + state.major = std::stoull(lines[1]); + } catch (...) { ; } + + return state; +} + +void CDonationNagManager::writeState(const SStateData& s) { + static const auto DATAROOT = NFsUtils::getDataHome(); + NFsUtils::writeToFile(*DATAROOT + "/" + LAST_NAG_FILE_NAME, std::format("{}\n{}", s.epoch, s.major)); +} diff --git a/src/managers/DonationNagManager.hpp b/src/managers/DonationNagManager.hpp index 357f979f..ce6015de 100644 --- a/src/managers/DonationNagManager.hpp +++ b/src/managers/DonationNagManager.hpp @@ -10,7 +10,16 @@ class CDonationNagManager { bool fired(); private: - bool m_bFired = false; + struct SStateData { + uint64_t epoch = 0; + uint64_t major = 0; + }; + + SStateData getState(); + void writeState(const SStateData& s); + void fire(); + + bool m_bFired = false; }; inline UP g_pDonationNagManager; \ No newline at end of file