aboutsummaryrefslogtreecommitdiffstats
path: root/src/m_ver_check/UpdateChecker.cpp
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2026-09-24 23:25:25 +0200
committersaturneric <[email protected]>2026-09-24 23:25:25 +0200
commit1c95ebf2cbb4d4c841141f568eb394f4091b6ba7 (patch)
treeedc4ae7cddc999d9500cc10dd6c83821c14fd9e0 /src/m_ver_check/UpdateChecker.cpp
parentfeat(update): add robust GitHub update checking (diff)
downloadmodules-1c95ebf2cbb4d4c841141f568eb394f4091b6ba7.tar.gz
modules-1c95ebf2cbb4d4c841141f568eb394f4091b6ba7.zip
feat(update): track unseen releases without prompting
- replace startup dialogs with quiet background update checks - track and persist the latest update seen by the user - expose update attention state for badges and UI indicators - acknowledge updates when the update page is opened - retain acknowledgements across failures, restarts, and rebuilds - expand tests for attention, persistence, and rediscovered releases
Diffstat (limited to 'src/m_ver_check/UpdateChecker.cpp')
-rw-r--r--src/m_ver_check/UpdateChecker.cpp31
1 files changed, 28 insertions, 3 deletions
diff --git a/src/m_ver_check/UpdateChecker.cpp b/src/m_ver_check/UpdateChecker.cpp
index 82f62b3..d65ca03 100644
--- a/src/m_ver_check/UpdateChecker.cpp
+++ b/src/m_ver_check/UpdateChecker.cpp
@@ -28,6 +28,8 @@
#include "UpdateChecker.h"
+#include <GFSDKApp.h>
+
#include <QJsonDocument>
#include <QJsonObject>
#include <QPointer>
@@ -60,6 +62,13 @@ auto UpdateChecker::IsFresh() const -> bool {
good->checked_at.secsTo(clock_()) < kFreshSeconds;
}
+void UpdateChecker::Acknowledge() {
+ if (AttentionFor(state_) == UpdateAttention::kNone) return;
+ state_.last_seen_update_version = state_.last_good->list.latest.version;
+ if (store_.save) store_.save(ToStorage(state_));
+ emit Changed();
+}
+
void UpdateChecker::Start(CheckMode mode) {
if (state_.checking) return;
if (mode == CheckMode::kIfStale && IsFresh()) return;
@@ -130,6 +139,9 @@ auto UpdateChecker::ToStorage(const UpdateSnapshot& s) -> QByteArray {
obj["last_attempt"] = s.last_attempt.toSecsSinceEpoch();
}
obj["last_attempt_failed"] = s.last_attempt_failed;
+ if (!s.last_seen_update_version.isEmpty()) {
+ obj["last_seen_update_version"] = s.last_seen_update_version;
+ }
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
}
@@ -142,6 +154,10 @@ auto UpdateChecker::FromStorage(const QByteArray& data, const Build& build)
const auto obj = doc.object();
if (obj.value("schema").toInt() != kStorageSchema) return s;
+ // Which update the user has seen is not a fact about this build: an
+ // upgrade, or a rebuild, must not advertise it again.
+ s.last_seen_update_version = obj.value("last_seen_update_version").toString();
+
auto good = SoftwareVersion::FromJson(obj.value("last_good").toObject());
// What was learned about another build says nothing about this one, and
// neither does how asking about it went.
@@ -156,7 +172,16 @@ auto UpdateChecker::FromStorage(const QByteArray& data, const Build& build)
return s;
}
-auto ShouldPromptOnStartup(const UpdateSnapshot& s) -> bool {
- return !s.checking && s.last_good &&
- ShouldPromptAtStartup(Decide(*s.last_good));
+auto AttentionFor(const UpdateSnapshot& s) -> UpdateAttention {
+ if (!s.last_good || Decide(*s.last_good) != Verdict::kUpdateAvailable) {
+ return UpdateAttention::kNone;
+ }
+ const auto& latest = s.last_good->list.latest.version;
+ const auto& seen = s.last_seen_update_version;
+ if (!seen.isEmpty() &&
+ GFCompareSoftwareVersion(latest.toUtf8().constData(),
+ seen.toUtf8().constData()) <= 0) {
+ return UpdateAttention::kNone;
+ }
+ return UpdateAttention::kUpdateAvailable;
}