Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions Cotabby/Services/Utilities/AppUpdateManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ final class AppUpdateManager {

private var isStarted = false

/// Sparkle persists this setting in user defaults, which take precedence over the value in
/// `CotabbyInfo.plist`. Reapplying the product policy repairs older installs that may have saved
/// a shorter development interval while the plist still gives fresh installs the same default.
private static let automaticCheckInterval: TimeInterval = 24 * 60 * 60

private static let debugCheckForUpdatesOnLaunchArgument = "-Cotabby-check-for-updates-on-launch"
private static let publicKeyPlaceholder = "REPLACE_WITH_GENERATED_SPARKLE_PUBLIC_ED_KEY"

Expand Down Expand Up @@ -53,18 +58,21 @@ final class AppUpdateManager {
return
}

// Configure the interval before starting so Sparkle's first scheduling decision uses the
// daily cadence together with its persisted last-check date.
let updater = updaterController.updater
updater.updateCheckInterval = Self.automaticCheckInterval
updaterController.startUpdater()
Comment thread
greptile-apps[bot] marked this conversation as resolved.
isStarted = true
log("Sparkle updater started.")

// Check once on every launch. Sparkle's scheduled check only fires on launch when the
// interval has already elapsed, so frequent users (who reopen within a day) would never
// see a check on open. This is a *background* check: it silently does nothing when the app
// is up to date and only surfaces UI when an update is actually available — unlike
// `checkForUpdates()`, which always shows a result dialog and is reserved for the manual
// "Check for Updates" button. The daily `SUScheduledCheckInterval` then covers long-running
// sessions where the app stays open for days.
updaterController.updater.checkForUpdatesInBackground()
// Catch up immediately when the app returns after the daily interval. Recent launches leave
// the check to Sparkle's scheduler, so reopening Cotabby cannot bypass the daily cadence.
let shouldCatchUp = updater.lastUpdateCheckDate
.map { Date().timeIntervalSince($0) >= Self.automaticCheckInterval } ?? true
if shouldCatchUp {
updater.checkForUpdatesInBackground()
}
Comment on lines +73 to +75

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Respect Disabled Checks

When automatic update checks are disabled, this catch-up path can still call checkForUpdatesInBackground() after the stored last-check date is missing or older than 24 hours. That makes launch contact the update feed even though the user disabled automatic checks. Gate the catch-up call on automaticallyChecksForUpdates so manual checks still work while automatic launch checks stay off.

Suggested change
if shouldCatchUp {
updater.checkForUpdatesInBackground()
}
if updater.automaticallyChecksForUpdates && shouldCatchUp {
updater.checkForUpdatesInBackground()
}

Fix in Codex Fix in Claude Code


#if DEBUG
if ProcessInfo.processInfo.arguments.contains(Self.debugCheckForUpdatesOnLaunchArgument) {
Expand Down
Loading