diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index da34e5f..eeaa3d4 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 63EAA4EB259944450046AB8F /* ProgressButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63EAA4EA259944450046AB8F /* ProgressButton.swift */; }; B0403CF02AD92D7B00137C09 /* ReleaseNotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */; }; B0403CF22AD934B600137C09 /* CompatibilityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CF12AD934B600137C09 /* CompatibilityView.swift */; }; + B0403CF42AD9381D00137C09 /* SDKsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CF32AD9381D00137C09 /* SDKsView.swift */; }; B0C6AD042AD6E65700E64698 /* ReleaseDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C6AD032AD6E65700E64698 /* ReleaseDateView.swift */; }; B0C6AD0B2AD9178E00E64698 /* IdenticalBuildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C6AD0A2AD9178E00E64698 /* IdenticalBuildView.swift */; }; B0C6AD0D2AD91D7900E64698 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C6AD0C2AD91D7900E64698 /* IconView.swift */; }; @@ -199,6 +200,7 @@ AB4EB0DE28541FA000FF3B1D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseNotesView.swift; sourceTree = ""; }; B0403CF12AD934B600137C09 /* CompatibilityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompatibilityView.swift; sourceTree = ""; }; + B0403CF32AD9381D00137C09 /* SDKsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKsView.swift; sourceTree = ""; }; B0C6AD032AD6E65700E64698 /* ReleaseDateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseDateView.swift; sourceTree = ""; }; B0C6AD0A2AD9178E00E64698 /* IdenticalBuildView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdenticalBuildView.swift; sourceTree = ""; }; B0C6AD0C2AD91D7900E64698 /* IconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconView.swift; sourceTree = ""; }; @@ -626,6 +628,7 @@ isa = PBXGroup; children = ( B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */, + B0403CF32AD9381D00137C09 /* SDKsView.swift */, B0403CF12AD934B600137C09 /* CompatibilityView.swift */, CAFBDC67259A308B003DCC5A /* InfoPane.swift */, E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */, @@ -902,6 +905,7 @@ CABFAA2D2592FBFC00380FEE /* Configure.swift in Sources */, CA73510D257BFCEF00EA9CF8 /* NSAttributedString+.swift in Sources */, CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */, + B0403CF42AD9381D00137C09 /* SDKsView.swift in Sources */, CAC9F92D25BCDA4400B4965F /* HelperInstallState.swift in Sources */, E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */, CAC281CD259F97FA00B8AB0B /* ObservingProgressIndicator.swift in Sources */, diff --git a/Xcodes/Frontend/InfoPane/InfoPane.swift b/Xcodes/Frontend/InfoPane/InfoPane.swift index f57052f..f617165 100644 --- a/Xcodes/Frontend/InfoPane/InfoPane.swift +++ b/Xcodes/Frontend/InfoPane/InfoPane.swift @@ -2,8 +2,8 @@ import AppKit import Path import SwiftUI import Version -import struct XCModel.SDKs import struct XCModel.Compilers +import struct XCModel.SDKs struct InfoPane: View { @EnvironmentObject var appState: AppState @@ -18,12 +18,12 @@ struct InfoPane: View { Text(verbatim: "Xcode \(xcode.description) \(xcode.version.buildMetadataIdentifiersDisplay)") .font(.title) - + switch xcode.installState { case .notInstalled: InstallButton(xcode: xcode) downloadFileSize(for: xcode) - case .installing(let installationStep): + case let .installing(installationStep): InstallationStepDetailView(installationStep: installationStep) .fixedSize(horizontal: false, vertical: true) CancelInstallButton(xcode: xcode) @@ -36,32 +36,32 @@ struct InfoPane: View { .buttonStyle(PlainButtonStyle()) .help("RevealInFinder") } - + HStack { SelectButton(xcode: xcode) .disabled(xcode.selected) .help("Selected") - + OpenButton(xcode: xcode) .help("Open") - + Spacer() UninstallButton(xcode: xcode) } } - + Divider() - Group{ + Group { ReleaseNotesView(url: xcode.releaseNotesURL) ReleaseDateView(date: xcode.releaseDate) .frame(maxWidth: .infinity, alignment: .leading) IdenticalBuildsView(builds: xcode.identicalBuilds) CompatibilityView(requiredMacOSVersion: xcode.requiredMacOSVersion) - sdks(for: xcode) + SDKsView(sdks: xcode.sdks) compilers(for: xcode) } - + Spacer() } .padding() @@ -72,34 +72,7 @@ struct InfoPane: View { .frame(minWidth: 200, maxWidth: .infinity) } } - - @ViewBuilder - private func sdks(for xcode: Xcode) -> some View { - if let sdks = xcode.sdks { - VStack(alignment: .leading) { - Text("SDKs") - .font(.headline) - .frame(maxWidth: .infinity, alignment: .leading) - - ForEach([ - ("macOS", \SDKs.macOS), - ("iOS", \.iOS), - ("watchOS", \.watchOS), - ("tvOS", \.tvOS), - ("visionOS", \.visionOS), - ], id: \.0) { row in - if let sdk = sdks[keyPath: row.1] { - Text("\(row.0): \(sdk.compactMap { $0.number }.joined(separator: ", "))") - .font(.subheadline) - .frame(maxWidth: .infinity, alignment: .leading) - } - } - } - } else { - EmptyView() - } - } - + @ViewBuilder private func compilers(for xcode: Xcode) -> some View { if let compilers = xcode.compilers { @@ -107,7 +80,7 @@ struct InfoPane: View { Text("Compilers") .font(.headline) .frame(maxWidth: .infinity, alignment: .leading) - + ForEach([ ("Swift", \Compilers.swift), ("Clang", \.clang), @@ -126,7 +99,7 @@ struct InfoPane: View { EmptyView() } } - + @ViewBuilder private func downloadFileSize(for xcode: Xcode) -> some View { // if we've downloaded it no need to show the download size @@ -143,7 +116,7 @@ struct InfoPane: View { EmptyView() } } - + @ViewBuilder private var empty: some View { Text("NoXcodeSelected") @@ -181,8 +154,8 @@ struct InfoPane_Previews: PreviewProvider { clang: .init(number: "7.3"), swift: .init(number: "5.3.2") ), - downloadFileSize: 242342424 - ) + downloadFileSize: 242_342_424 + ), ] }) .previewDisplayName("Populated, Installed, Selected") @@ -208,7 +181,8 @@ struct InfoPane_Previews: PreviewProvider { clang: .init(number: "7.3"), swift: .init(number: "5.3.2") ), - downloadFileSize: 242342424) + downloadFileSize: 242_342_424 + ), ] }) .previewDisplayName("Populated, Installed, Unselected") @@ -234,7 +208,8 @@ struct InfoPane_Previews: PreviewProvider { clang: .init(number: "7.3"), swift: .init(number: "5.3.2") ), - downloadFileSize: 242342424) + downloadFileSize: 242_342_424 + ), ] }) .previewDisplayName("Populated, Uninstalled") @@ -248,7 +223,8 @@ struct InfoPane_Previews: PreviewProvider { selected: false, icon: nil, sdks: nil, - compilers: nil) + compilers: nil + ), ] }) .previewDisplayName("Basic, installed") @@ -258,15 +234,16 @@ struct InfoPane_Previews: PreviewProvider { $0.allXcodes = [ .init( version: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]), - installState: .installing(.downloading(progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40; $0.throughput = 232323232; $0.fileCompletedCount = 2323004; $0.fileTotalCount = 1193939393 })), + installState: .installing(.downloading(progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40; $0.throughput = 232_323_232; $0.fileCompletedCount = 2_323_004; $0.fileTotalCount = 1_193_939_393 })), selected: false, icon: nil, sdks: nil, - compilers: nil) + compilers: nil + ), ] }) .previewDisplayName("Basic, installing") - + InfoPane(selectedXcodeID: nil) .environmentObject(configure(AppState()) { $0.allXcodes = [ diff --git a/Xcodes/Frontend/InfoPane/SDKsView.swift b/Xcodes/Frontend/InfoPane/SDKsView.swift new file mode 100644 index 0000000..f2d3ed9 --- /dev/null +++ b/Xcodes/Frontend/InfoPane/SDKsView.swift @@ -0,0 +1,81 @@ +// +// SDKsView.swift +// Xcodes +// +// Created by Duong Thai on 13/10/2023. +// Copyright © 2023 Robots and Pencils. All rights reserved. +// + +import SwiftUI +import struct XCModel.SDKs + +struct SDKsView: View { + let sdks: SDKs? + + var body: some View { + if let sdks = sdks { + VStack(alignment: .leading) { + Text("SDKs").font(.headline) + Text(Self.content(from: sdks)).font(.subheadline) + } + } else { + EmptyView() + } + } + + static private func content(from sdks: SDKs) -> String { + let content: String = [ + ("macOS", sdks.macOS), + ("iOS", sdks.iOS), + ("watchOS", sdks.watchOS), + ("tvOS", sdks.tvOS) + ].compactMap { // remove nil compiler + guard $0.1 != nil, // has version array + !$0.1!.isEmpty // has at least 1 version + else { return nil } + + let numbers = $0.1!.compactMap { $0.number } // remove nil number + guard !numbers.isEmpty // has at least 1 number + else { return nil } + + // description for each type of compilers + return "\($0.0): \(numbers.joined(separator: ", "))" + }.joined(separator: "\n") + + return content + } +} + +struct SDKsView_Preview: PreviewProvider { + static var previews: some View { + WrapperView() + } +} + +private struct WrapperView: View { + @State var isNil = false + var sdks: SDKs? { + isNil + ? nil + : SDKs(macOS: .init(number: "11.1"), + iOS: .init(number: "14.3"), + watchOS: .init(number: "7.3"), + tvOS: .init(number: "14.3")) + } + + var body: some View { + VStack { + HStack { + SDKsView(sdks: sdks) + .border(.red) + } + Spacer() + Toggle(isOn: $isNil) { + Text("Is Nil?") + } + } + .animation(.default) + .frame(width: 200, height: 100) + .padding() + } +}