Description of the feature
Add the ability for the application to check for new versions via the GitHub Releases API and inform the user when an update is available. No auto-update — the user is directed to the GitHub release page to download manually.
The feature is completely disabled for Microsoft Store installs, as the Store handles updates natively. For all other distributions (portable executable, self-signed MSIX, developer builds), the update checker is active and includes both stable and pre-release versions.
Use case
Users of the portable (non-Store) distribution have no way to know when a new version is available. They must manually check the GitHub releases page. This feature provides a lightweight, non-intrusive notification mechanism so users stay informed about new releases without leaving the app.
Proposed solution
API Integration
- Endpoint:
GET https://api.github.com/repos/TimGels/Matroska-Batch-Flow/releases?per_page=20
- Unauthenticated, public repo (rate limit: 60 requests/hour/IP)
- Uses the list endpoint (not
/releases/latest) so that pre-releases are included
- The service iterates the response to find the newest release (stable or pre-release) with a
tag_name newer than the current app version, skipping drafts
- Relevant fields per release:
tag_name, html_url, published_at, prerelease, draft
Store Detection
Disable the feature for Store installs using PackageSignatureKind:
#if WINDOWS10_0_19041_0_OR_GREATER
bool isStore = Package.Current.SignatureKind == PackageSignatureKind.Store;
#endif
This distinguishes between:
- Store-signed MSIX → update check disabled
- Self-signed / developer MSIX → update check enabled
- Unpackaged portable app → update check enabled
Add AppEnvironmentHelper.IsStoreDistribution() helper method.
Version Comparison
Use NuGet.Versioning.SemanticVersion for correct pre-release ordering (1.0.0-alpha < 1.0.0-beta < 1.0.0). Parse tag_name by stripping the v prefix and compare against the current app version.
Caching — UpdateState.json
Cached API state is stored separately from UserSettings.json via WritableJsonSettings<UpdateState>:
{
"LastSuccessfulCheck": "2026-02-20T14:30:00Z",
"LatestKnownVersion": "1.3.0",
"IsPreRelease": false,
"ReleaseUrl": "https://github.com/TimGels/Matroska-Batch-Flow/releases/tag/v1.3.0",
"PublishedAt": "2026-02-19T10:00:00Z",
"SkippedVersion": null
}
Startup cache logic:
- Read
UpdateState.json
- If
LatestKnownVersion > currentAppVersion AND LatestKnownVersion != SkippedVersion → show notification immediately from cache (no API call)
- If
LastSuccessfulCheck is null OR (UtcNow - LastSuccessfulCheck) >= 1 hour → fetch from GitHub API, update UpdateState.json → show notification if newer version found
- Otherwise: cache is fresh, no action needed
Service Architecture
The service lives in Core (pure HTTP + JSON deserialization + version comparison, no UI dependency):
Core:
Models/UpdateInfo.cs — record with version, URL, date, prerelease flag
Services/IUpdateCheckService.cs — interface: CheckForUpdateAsync(CancellationToken)
Services/GitHubUpdateCheckService.cs — HttpClient implementation
Logging/GitHubUpdateCheckService.Logging.cs — LoggerMessage source generators
Store detection, caching decisions, and opt-out checks are the caller's responsibility (ViewModel / App startup in Uno).
UX — Notification Patterns
Several patterns can be combined (exact selection to be decided during implementation):
- InfoBar on the Settings page —
InfoBar showing "Version X.Y.Z is available" with a "View Release" action button that opens the GitHub release page in the default browser
- Dialog on startup — Content dialog shown once after startup with version, date, and a "View Release" button
- Badge on the Settings nav item —
InfoBadge dot on the Settings icon for passive awareness
UX — Manual Check
- "Check for Updates" button on the Settings page (About section)
- Bypasses the 1-hour cache
- Rate-limited (e.g., button disabled for 30 seconds after a check) to be a good citizen of the GitHub API
- Shows a brief loading state, then the result (update available or up-to-date)
UX — User Preferences
- "Check for updates on startup" toggle in Settings (default: enabled, only shown for non-Store installs)
- Skip version — "Don't remind me about this version" stored in
UpdateState.json as SkippedVersion
Error Handling & Logging
- Timeout: 5 seconds — fail fast for offline scenarios
- Catch all exceptions, log at Debug level, silently return "no update available"
- Never block app startup for the update check (fire-and-forget async after activation)
LoggerMessage source generators in a separate .Logging.cs partial class
Alternatives considered
- In-app release notes rendering: GitHub release notes are Markdown; WinUI 3 / Uno Platform has no reliable cross-platform Markdown rendering control (the Community Toolkit
MarkdownTextBlock is not reliable on Skia). Instead, the user is directed to the GitHub release page via a link/button.
Raw HttpClient with the GitHub Releases API was chosen: ~50 lines of service code, zero external dependencies (beyond NuGet.Versioning), full UX control.
Additional information
Startup integration
The update check runs as a fire-and-forget async operation after activation completes. It only runs if:
- User hasn't opted out (
CheckForUpdatesOnStartup in UserSettings)
- App is not a Store install (
!IsStoreDistribution())
- Cache TTL (1 hour) has expired
UserSettings.UISettings addition
Only the user preference toggle:
[JsonPropertyName("CheckForUpdatesOnStartup")]
public bool CheckForUpdatesOnStartup { get; set; } = true;
Open design questions
- Should the
HttpClient be configured via IHttpClientFactory (recommended for resilience) or a simple singleton?
- What is the exact badge/indicator UX for the navigation item? (
InfoBadge with attention dot vs. numeric badge vs. icon overlay)
- Should the skipped version persist across app restarts, or reset each session?
- Should the UI differentiate between stable and pre-release updates (e.g., different InfoBar severity, a "Pre-release" label)?
- When multiple newer releases exist (e.g., a stable and a pre-release), should the notification show the newest overall, or the newest stable?
Scope exclusions
- No auto-download or auto-install
- No GitHub Actions release workflow (separate concern)
- No update checking for Microsoft Store installs
- No in-app display of release notes
Description of the feature
Add the ability for the application to check for new versions via the GitHub Releases API and inform the user when an update is available. No auto-update — the user is directed to the GitHub release page to download manually.
The feature is completely disabled for Microsoft Store installs, as the Store handles updates natively. For all other distributions (portable executable, self-signed MSIX, developer builds), the update checker is active and includes both stable and pre-release versions.
Use case
Users of the portable (non-Store) distribution have no way to know when a new version is available. They must manually check the GitHub releases page. This feature provides a lightweight, non-intrusive notification mechanism so users stay informed about new releases without leaving the app.
Proposed solution
API Integration
GET https://api.github.com/repos/TimGels/Matroska-Batch-Flow/releases?per_page=20/releases/latest) so that pre-releases are includedtag_namenewer than the current app version, skipping draftstag_name,html_url,published_at,prerelease,draftStore Detection
Disable the feature for Store installs using
PackageSignatureKind:This distinguishes between:
Add
AppEnvironmentHelper.IsStoreDistribution()helper method.Version Comparison
Use
NuGet.Versioning.SemanticVersionfor correct pre-release ordering (1.0.0-alpha < 1.0.0-beta < 1.0.0). Parsetag_nameby stripping thevprefix and compare against the current app version.Caching —
UpdateState.jsonCached API state is stored separately from
UserSettings.jsonviaWritableJsonSettings<UpdateState>:{ "LastSuccessfulCheck": "2026-02-20T14:30:00Z", "LatestKnownVersion": "1.3.0", "IsPreRelease": false, "ReleaseUrl": "https://github.com/TimGels/Matroska-Batch-Flow/releases/tag/v1.3.0", "PublishedAt": "2026-02-19T10:00:00Z", "SkippedVersion": null }Startup cache logic:
UpdateState.jsonLatestKnownVersion > currentAppVersionANDLatestKnownVersion != SkippedVersion→ show notification immediately from cache (no API call)LastSuccessfulCheckis null OR(UtcNow - LastSuccessfulCheck) >= 1 hour→ fetch from GitHub API, updateUpdateState.json→ show notification if newer version foundService Architecture
The service lives in Core (pure HTTP + JSON deserialization + version comparison, no UI dependency):
Store detection, caching decisions, and opt-out checks are the caller's responsibility (ViewModel / App startup in Uno).
UX — Notification Patterns
Several patterns can be combined (exact selection to be decided during implementation):
InfoBarshowing "Version X.Y.Z is available" with a "View Release" action button that opens the GitHub release page in the default browserInfoBadgedot on the Settings icon for passive awarenessUX — Manual Check
UX — User Preferences
UpdateState.jsonasSkippedVersionError Handling & Logging
LoggerMessagesource generators in a separate.Logging.cspartial classAlternatives considered
MarkdownTextBlockis not reliable on Skia). Instead, the user is directed to the GitHub release page via a link/button.Raw
HttpClientwith the GitHub Releases API was chosen: ~50 lines of service code, zero external dependencies (beyondNuGet.Versioning), full UX control.Additional information
Startup integration
The update check runs as a fire-and-forget async operation after activation completes. It only runs if:
CheckForUpdatesOnStartupinUserSettings)!IsStoreDistribution())UserSettings.UISettingsadditionOnly the user preference toggle:
Open design questions
HttpClientbe configured viaIHttpClientFactory(recommended for resilience) or a simple singleton?InfoBadgewith attention dot vs. numeric badge vs. icon overlay)Scope exclusions