diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index 7e67ee0..88c61ec 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -100,7 +100,6 @@ CAFE4ABC25B7D54B0064FE51 /* UpdatesPreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFE4ABB25B7D54B0064FE51 /* UpdatesPreferencePane.swift */; }; CAFFFED8259CDA5000903F81 /* XcodeListViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */; }; E8977EA325C11E1500835F80 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8977EA225C11E1500835F80 /* PreferencesView.swift */; }; - E8C891DA25C8DC6D00F1D3C4 /* Double+formatBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8C891D925C8DC6D00F1D3C4 /* Double+formatBytes.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -262,7 +261,6 @@ CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeListViewRow.swift; sourceTree = ""; }; CAFFFEEE259CEAC400903F81 /* RingProgressViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RingProgressViewStyle.swift; sourceTree = ""; }; E8977EA225C11E1500835F80 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = ""; }; - E8C891D925C8DC6D00F1D3C4 /* Double+formatBytes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+formatBytes.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -413,7 +411,6 @@ CABFAA482593162500380FEE /* Bundle+InfoPlistValues.swift */, CA9FF87A2595293E00E47BAF /* DataSource.swift */, CABFA9BA2592EEEA00380FEE /* DateFormatter+.swift */, - E8C891D925C8DC6D00F1D3C4 /* Double+formatBytes.swift */, CABFA9B92592EEEA00380FEE /* Downloads.swift */, CAA858C325A2BE4E00ACF8C0 /* Downloader.swift */, CABFA9B22592EEEA00380FEE /* Entry+.swift */, @@ -795,7 +792,6 @@ CABFA9C72592EEEA00380FEE /* Entry+.swift in Sources */, CAE424B4259A764700B8B246 /* AppState+Install.swift in Sources */, CAE42487259A68A300B8B246 /* XcodeListCategory.swift in Sources */, - E8C891DA25C8DC6D00F1D3C4 /* Double+formatBytes.swift in Sources */, CAA858C425A2BE4E00ACF8C0 /* Downloader.swift in Sources */, E8977EA325C11E1500835F80 /* PreferencesView.swift in Sources */, CA9FF87B2595293E00E47BAF /* DataSource.swift in Sources */, diff --git a/Xcodes/Backend/AvailableXcode.swift b/Xcodes/Backend/AvailableXcode.swift index 92bef4f..cf3f0e4 100644 --- a/Xcodes/Backend/AvailableXcode.swift +++ b/Xcodes/Backend/AvailableXcode.swift @@ -13,7 +13,7 @@ public struct AvailableXcode: Codable { public let releaseNotesURL: URL? public let sdks: SDKs? public let compilers: Compilers? - public let fileSize: Double? + public let fileSize: Int64? public init( version: Version, @@ -24,7 +24,7 @@ public struct AvailableXcode: Codable { releaseNotesURL: URL? = nil, sdks: SDKs? = nil, compilers: Compilers? = nil, - fileSize: Double? = nil + fileSize: Int64? = nil ) { self.version = version self.url = url diff --git a/Xcodes/Backend/Double+formatBytes.swift b/Xcodes/Backend/Double+formatBytes.swift deleted file mode 100644 index 64bd843..0000000 --- a/Xcodes/Backend/Double+formatBytes.swift +++ /dev/null @@ -1,24 +0,0 @@ - -import Foundation - -extension Double { - func formatAsString() -> String { - guard self > 0 else { - return "0 bytes" - } - - // Adapted from http://stackoverflow.com/a/18650828 - let suffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] - let k: Double = 1000 - let i = floor(log(self) / log(k)) - - // Format number with thousands separator and everything below 1 GB with no decimal places. - let numberFormatter = NumberFormatter() - numberFormatter.maximumFractionDigits = i < 3 ? 0 : 1 - numberFormatter.numberStyle = .decimal - - let numberString = numberFormatter.string(from: NSNumber(value: self / pow(k, i))) ?? "Unknown" - let suffix = suffixes[Int(i)] - return "\(numberString) \(suffix)" - } -} diff --git a/Xcodes/Backend/Downloads.swift b/Xcodes/Backend/Downloads.swift index 8694bd8..55096e4 100644 --- a/Xcodes/Backend/Downloads.swift +++ b/Xcodes/Backend/Downloads.swift @@ -6,6 +6,9 @@ struct Downloads: Codable { let downloads: [Download] } +// Set to Int64 as ByteCountFormatter uses it. +public typealias ByteCount = Int64 + public struct Download: Codable { public let name: String public let files: [File] @@ -13,6 +16,6 @@ public struct Download: Codable { public struct File: Codable { public let remotePath: String - public let fileSize: Double + public let fileSize: ByteCount } } diff --git a/Xcodes/Backend/Xcode.swift b/Xcodes/Backend/Xcode.swift index a8e448c..a5da1bc 100644 --- a/Xcodes/Backend/Xcode.swift +++ b/Xcodes/Backend/Xcode.swift @@ -13,7 +13,7 @@ struct Xcode: Identifiable, CustomStringConvertible { let releaseNotesURL: URL? let sdks: SDKs? let compilers: Compilers? - let downloadFileSize: Double? + let downloadFileSize: Int64? init( version: Version, @@ -24,7 +24,7 @@ struct Xcode: Identifiable, CustomStringConvertible { releaseNotesURL: URL? = nil, sdks: SDKs? = nil, compilers: Compilers? = nil, - downloadFileSize: Double? = nil + downloadFileSize: Int64? = nil ) { self.version = version self.installState = installState @@ -44,6 +44,10 @@ struct Xcode: Identifiable, CustomStringConvertible { } var downloadFileSizeString: String? { - return downloadFileSize?.formatAsString() + if let downloadFileSize = downloadFileSize { + return ByteCountFormatter.string(fromByteCount: downloadFileSize, countStyle: .file) + } else { + return nil + } } } diff --git a/Xcodes/Frontend/XcodeList/InfoPane.swift b/Xcodes/Frontend/XcodeList/InfoPane.swift index 99fddd8..382138b 100644 --- a/Xcodes/Frontend/XcodeList/InfoPane.swift +++ b/Xcodes/Frontend/XcodeList/InfoPane.swift @@ -245,7 +245,8 @@ struct InfoPane_Previews: PreviewProvider { llvm: .init(number: "2.3"), clang: .init(number: "7.3"), swift: .init(number: "5.3.2") - )) + ), + downloadFileSize: 242342424) ] }) .previewDisplayName("Populated, Installed, Unselected") @@ -270,7 +271,8 @@ struct InfoPane_Previews: PreviewProvider { llvm: .init(number: "2.3"), clang: .init(number: "7.3"), swift: .init(number: "5.3.2") - )) + ), + downloadFileSize: 242342424) ] }) .previewDisplayName("Populated, Uninstalled") diff --git a/XcodesTests/AppStateTests.swift b/XcodesTests/AppStateTests.swift index c9fffb2..0c4c165 100644 --- a/XcodesTests/AppStateTests.swift +++ b/XcodesTests/AppStateTests.swift @@ -89,7 +89,7 @@ class AppStateTests: XCTestCase { } // It's an available release version else if urlRequest.url! == URLRequest.downloads.url! { - let downloads = Downloads(downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip")], dateModified: Date())]) + let downloads = Downloads(downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip", fileSize: 9484444)], dateModified: Date())]) let encoder = JSONEncoder() encoder.dateEncodingStrategy = .formatted(.downloadsDateModified) let downloadsData = try! encoder.encode(downloads) @@ -199,7 +199,7 @@ class AppStateTests: XCTestCase { } // It's an available release version else if urlRequest.url! == URLRequest.downloads.url! { - let downloads = Downloads(downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip")], dateModified: Date())]) + let downloads = Downloads(downloads: [Download(name: "Xcode 0.0.0", files: [Download.File(remotePath: "https://apple.com/xcode.xip", fileSize: 9494944)], dateModified: Date())]) let encoder = JSONEncoder() encoder.dateEncodingStrategy = .formatted(.downloadsDateModified) let downloadsData = try! encoder.encode(downloads)