diff --git a/Sources/Model/API/ServerInfo.swift b/Sources/Model/API/ServerInfo.swift index 67cd172..d7fc1f7 100644 --- a/Sources/Model/API/ServerInfo.swift +++ b/Sources/Model/API/ServerInfo.swift @@ -65,8 +65,9 @@ struct ServerInfo: Codable, Hashable, Equatable { } struct PHPInterpreter: Codable, Hashable, Identifiable, Equatable { - var id: String { versionFull } + var id: String { [fullVersion, path ?? ""].joined(separator: "|") } let version: String + let fullVersion: String let path: String? let configFile: String? let extensions: [String] @@ -75,6 +76,7 @@ struct ServerInfo: Codable, Hashable, Equatable { init( version: String, + fullVersion: String? = nil, path: String? = nil, configFile: String? = nil, extensions: [String] = [], @@ -82,6 +84,7 @@ struct ServerInfo: Codable, Hashable, Equatable { maxExecutionTime: String? = nil ) { self.version = version + self.fullVersion = fullVersion ?? version self.path = path self.configFile = configFile self.extensions = extensions @@ -89,8 +92,8 @@ struct ServerInfo: Codable, Hashable, Equatable { self.maxExecutionTime = maxExecutionTime } - var versionFull: String { - var components = [version] + var versionWithPath: String { + var components = [fullVersion] if let path, !path.isEmpty { components.append(path) } @@ -162,10 +165,16 @@ struct ServerInfo: Codable, Hashable, Equatable { } var formattedServerTime: String { - guard let date = ServerInfo.isoFormatter.date(from: serverTime) else { - return serverTime + let normalizedServerTime = ServerInfo.normalizedServerTime(serverTime) + + if let date = ServerInfo.serverTimeParsers + .lazy + .compactMap({ $0.date(from: normalizedServerTime) }) + .first { + return ServerInfo.displayFormatter.string(from: date) } - return ServerInfo.displayFormatter.string(from: date) + + return serverTime } var operatingSystemSummary: String? { @@ -181,19 +190,42 @@ struct ServerInfo: Codable, Hashable, Equatable { // MARK: - Helpers & Sample Data extension ServerInfo { - private static let isoFormatter: ISO8601DateFormatter = { - let formatter = ISO8601DateFormatter() - formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds, .withColonSeparatorInTimeZone] - return formatter + private static let serverTimeParsers: [ISO8601DateFormatter] = { + let withFractional = ISO8601DateFormatter() + withFractional.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + + let withoutFractional = ISO8601DateFormatter() + withoutFractional.formatOptions = [.withInternetDateTime] + + let noColonTimeZone = ISO8601DateFormatter() + noColonTimeZone.formatOptions = [.withFullDate, .withTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone] + + return [withFractional, withoutFractional, noColonTimeZone] }() private static let displayFormatter: DateFormatter = { let formatter = DateFormatter() + formatter.locale = .autoupdatingCurrent formatter.dateStyle = .medium formatter.timeStyle = .medium return formatter }() + private static func normalizedServerTime(_ value: String) -> String { + if value.range(of: #"[+-]\d{2}:\d{2}$"#, options: .regularExpression) != nil { + return value + } + + guard value.range(of: #"[+-]\d{4}$"#, options: .regularExpression) != nil else { + return value + } + + var normalized = value + let insertionIndex = normalized.index(normalized.endIndex, offsetBy: -2) + normalized.insert(":", at: insertionIndex) + return normalized + } + static let placeholder = ServerInfo( hostname: "preview.example.com", ipAddresses: ["192.168.1.1", "fe80::1"], diff --git a/Sources/Model/API/Versions/APIv2_12.swift b/Sources/Model/API/Versions/APIv2_12.swift index 83dfbad..4225797 100644 --- a/Sources/Model/API/Versions/APIv2_12.swift +++ b/Sources/Model/API/Versions/APIv2_12.swift @@ -278,6 +278,7 @@ private extension APIv2_12 { struct AdditionalInterpreter: Decodable { let version: String + let versionFull: String? let path: String? let configFile: String? } @@ -398,6 +399,7 @@ private extension APIv2_12 { additionalPHPInterpreters: additionalPhpInterpreters?.map { ServerInfo.PHPInterpreter( version: $0.version, + fullVersion: $0.versionFull, path: $0.path, configFile: $0.configFile, extensions: [], diff --git a/Sources/Model/API/Versions/APIv2_13.swift b/Sources/Model/API/Versions/APIv2_13.swift index ec3fccd..1bb502e 100644 --- a/Sources/Model/API/Versions/APIv2_13.swift +++ b/Sources/Model/API/Versions/APIv2_13.swift @@ -278,6 +278,7 @@ private extension APIv2_13 { struct AdditionalInterpreter: Decodable { let version: String + let versionFull: String? let path: String? let configFile: String? } @@ -398,6 +399,7 @@ private extension APIv2_13 { additionalPHPInterpreters: additionalPhpInterpreters?.map { ServerInfo.PHPInterpreter( version: $0.version, + fullVersion: $0.versionFull, path: $0.path, configFile: $0.configFile, extensions: [], diff --git a/Sources/Views/Cells/InfoCell.swift b/Sources/Views/Cells/InfoCell.swift index 4e23236..d96ab31 100644 --- a/Sources/Views/Cells/InfoCell.swift +++ b/Sources/Views/Cells/InfoCell.swift @@ -5,12 +5,6 @@ // Created by tracer on 03.04.25. // -// -// ResourcesBarRow.swift -// iKeyMon -// -// Created by tracer on 31.03.25. -// import SwiftUI diff --git a/Sources/Views/Tabs/GeneralView.swift b/Sources/Views/Tabs/GeneralView.swift index 3eea132..22883fc 100644 --- a/Sources/Views/Tabs/GeneralView.swift +++ b/Sources/Views/Tabs/GeneralView.swift @@ -106,7 +106,13 @@ struct GeneralView: View { if interpreters.isEmpty { return ["None"] } - return interpreters.map { $0.versionFull } + let versions = interpreters + .map { $0.fullVersion } + .filter { !$0.isEmpty } + if versions.isEmpty { + return ["None"] + } + return [versions.joined(separator: " • ")] }(), monospaced: true ) diff --git a/Sparkle/appcast.xml b/Sparkle/appcast.xml index 823650e..41c0522 100644 --- a/Sparkle/appcast.xml +++ b/Sparkle/appcast.xml @@ -1,30 +1,30 @@ - - + + iKeyMon + + 26.0.27 + Sun, 07 Dec 2025 16:47:33 +0100 + 57 + 26.0.27 + 15.2 + + 26.0.21 Wed, 26 Nov 2025 18:44:41 +0100 - 49 - 26.0.21 - 15.2 - + 49 + 26.0.21 + 15.2 + 26.0.20 Wed, 26 Nov 2025 18:36:41 +0100 - 47 - 26.0.20 - 15.2 - - - - 26.0.16 - Tue, 25 Nov 2025 18:34:19 +0100 - 39 - 26.0.16 - 15.2 - + 47 + 26.0.20 + 15.2 + \ No newline at end of file diff --git a/iKeyMon.xcodeproj/project.pbxproj b/iKeyMon.xcodeproj/project.pbxproj index bb75d86..e577680 100644 --- a/iKeyMon.xcodeproj/project.pbxproj +++ b/iKeyMon.xcodeproj/project.pbxproj @@ -310,7 +310,7 @@ CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 56; + CURRENT_PROJECT_VERSION = 57; DEVELOPMENT_ASSET_PATHS = "\"Preview Content\""; DEVELOPMENT_TEAM = Q5486ZVAFT; ENABLE_HARDENED_RUNTIME = YES; @@ -325,7 +325,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 26.0.26; + MARKETING_VERSION = 26.0.27; PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -341,7 +341,7 @@ CODE_SIGN_ENTITLEMENTS = iKeyMon.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 56; + CURRENT_PROJECT_VERSION = 57; DEVELOPMENT_ASSET_PATHS = "\"Preview Content\""; DEVELOPMENT_TEAM = Q5486ZVAFT; ENABLE_HARDENED_RUNTIME = YES; @@ -356,7 +356,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 26.0.26; + MARKETING_VERSION = 26.0.27; PRODUCT_BUNDLE_IDENTIFIER = net.24unix.iKeyMon; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/scripts/build_release.sh b/scripts/build_release.sh index 35cb359..92a67bb 100755 --- a/scripts/build_release.sh +++ b/scripts/build_release.sh @@ -41,6 +41,9 @@ generate_appcast() { return fi + local sparkle_cache="$HOME/Library/Caches/Sparkle_generate_appcast" + rm -rf "$sparkle_cache" + local output="$SPARKLE_APPCAST_OUTPUT" mkdir -p "$(dirname "$output")" local staging_dir diff --git a/version.json b/version.json index c9985b1..b7370ac 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "marketing_version": "26.0.26" + "marketing_version": "26.0.27" }