vibetunnel/VibeTunnel/Core/Models/UpdateChannel.swift
Peter Steinberger c5a7bcc13f Fix build issues after dependency updates
- Add UserDefaults extension for KVO-compatible updateChannel property
- Fix HTTPField.Name API changes in AuthenticationMiddleware
- Add @preconcurrency annotations to SparkleUpdaterManager protocols
- Wrap KVO observer callback in Task { @MainActor } to fix concurrency warning
- Update deinit to avoid accessing MainActor-isolated properties

These changes address Swift 6 concurrency strictness and API changes
introduced in Hummingbird 2.14.1.
2025-06-16 00:49:38 +02:00

117 lines
3.7 KiB
Swift

import Foundation
/// Represents the available update channels for the application.
///
/// This enum defines the different update channels that users can choose from,
/// allowing them to receive either stable releases only or include pre-release versions.
public enum UpdateChannel: String, CaseIterable, Codable, Sendable {
case stable
case prerelease
/// Human-readable display name for the update channel
public var displayName: String {
switch self {
case .stable:
"Stable Only"
case .prerelease:
"Include Pre-releases"
}
}
/// Detailed description of what each channel includes
public var description: String {
switch self {
case .stable:
"Receive only stable, production-ready releases"
case .prerelease:
"Receive both stable releases and beta/pre-release versions"
}
}
/// The Sparkle appcast URL for this update channel
public var appcastURL: URL {
switch self {
case .stable:
Self.stableAppcastURL
case .prerelease:
Self.prereleaseAppcastURL
}
}
/// Static URLs to ensure they're validated at compile time
private static let stableAppcastURL: URL = {
guard let url = URL(string: "https://vibetunnel.sh/appcast.xml") else {
fatalError("Invalid stable appcast URL - this should never happen with a hardcoded URL")
}
return url
}()
private static let prereleaseAppcastURL: URL = {
guard let url = URL(string: "https://vibetunnel.sh/appcast-prerelease.xml") else {
fatalError("Invalid prerelease appcast URL - this should never happen with a hardcoded URL")
}
return url
}()
/// Whether this channel includes pre-release versions
public var includesPreReleases: Bool {
switch self {
case .stable:
false
case .prerelease:
true
}
}
/// The current update channel based on user defaults
public static var current: Self {
if let rawValue = UserDefaults.standard.string(forKey: "updateChannel"),
let channel = Self(rawValue: rawValue)
{
return channel
}
return defaultChannel
}
/// The default update channel based on the current app version
public static var defaultChannel: Self {
defaultChannel(for: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0")
}
/// Determines if the current app version suggests this channel should be default
public static func defaultChannel(for appVersion: String) -> Self {
// First check if this build was marked as a pre-release during build time
if let isPrereleaseValue = Bundle.main.object(forInfoDictionaryKey: "IS_PRERELEASE_BUILD"),
let isPrerelease = isPrereleaseValue as? Bool,
isPrerelease
{
return .prerelease
}
// Otherwise, check if the version string contains pre-release keywords
let prereleaseKeywords = ["beta", "alpha", "rc", "pre", "dev"]
let lowercaseVersion = appVersion.lowercased()
for keyword in prereleaseKeywords where lowercaseVersion.contains(keyword) {
return .prerelease
}
return .stable
}
}
// MARK: - Identifiable Conformance
extension UpdateChannel: Identifiable {
public var id: String { rawValue }
}
// MARK: - UserDefaults Integration
extension UserDefaults {
/// KVO-compatible property for update channel
@objc dynamic var updateChannel: String? {
get { string(forKey: "updateChannel") }
set { set(newValue, forKey: "updateChannel") }
}
}