Files
ios-gitea-prs/GiteaPR/Notifications/NotificationState.swift
T
Hermes bae531f850
Build iOS App / Build .ipa and publish source (push) Successful in 31s
Add push-equivalent notifications via background polling; bump to 3.6
Sideloaded apps can't use APNs (no push entitlement without Apple signing),
so deliver notifications via an iOS BGAppRefreshTask that polls the monitored
repos every ~15 min and fires local notifications (no Apple push needed):
- new PRs that appear in the open set
- CI status changes on existing PRs

Persistence: NotificationState tracks announced PR ids + last-known CI status
so we only fire on actual changes, not every poll. AppDelegate registers the
background task and reschedules the next one. Info.plist gets UIBackgroundModes
fetch + the BGTask identifier. Settings gains a Notifications toggle; also
poll after a foreground inbox load so state seeds and changes are caught
promptly. Bump to 3.6.
2026-08-24 08:18:29 +00:00

31 lines
1.1 KiB
Swift

import Foundation
/// Persisted "what we've already notified about", so the background poller
/// only fires a notification when something actually changes:
/// - a PR that wasn't there before → "new PR"
/// - a PR whose CI aggregate status changed → "CI status changed"
struct NotificationState: Codable {
/// PR ids (repo.fullName#number) we've already announced as new.
var announcedNewPRs: Set<String> = []
/// PR id → last notified CI status string ("success"/"failure"/"running"/etc).
var ciStatusByPR: [String: String] = [:]
private static let url: URL = {
let dir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
return dir.appendingPathComponent("notification-state.json")
}()
func save() {
guard let data = try? JSONEncoder().encode(self) else { return }
try? data.write(to: Self.url)
}
static func load() -> NotificationState {
guard let data = try? Data(contentsOf: url),
let state = try? JSONDecoder().decode(NotificationState.self, from: data) else {
return NotificationState()
}
return state
}
}