diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index 8bd4152..9ed058b 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 63EAA4EB259944450046AB8F /* ProgressButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63EAA4EA259944450046AB8F /* ProgressButton.swift */; }; CA11E7BA2598476C00D2EE1C /* XcodeCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA11E7B92598476C00D2EE1C /* XcodeCommands.swift */; }; + CA2518EC25A7FF2B00F08414 /* AppStateUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2518EB25A7FF2B00F08414 /* AppStateUpdateTests.swift */; }; CA378F992466567600A58CE0 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA378F982466567600A58CE0 /* AppState.swift */; }; CA39711924495F0E00AFFB77 /* AppStoreButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA39711824495F0E00AFFB77 /* AppStoreButtonStyle.swift */; }; CA44901F2463AD34003D8213 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA44901E2463AD34003D8213 /* Tag.swift */; }; @@ -132,6 +133,7 @@ /* Begin PBXFileReference section */ 63EAA4EA259944450046AB8F /* ProgressButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressButton.swift; sourceTree = ""; }; CA11E7B92598476C00D2EE1C /* XcodeCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeCommands.swift; sourceTree = ""; }; + CA2518EB25A7FF2B00F08414 /* AppStateUpdateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateUpdateTests.swift; sourceTree = ""; }; CA378F982466567600A58CE0 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; CA39711824495F0E00AFFB77 /* AppStoreButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStoreButtonStyle.swift; sourceTree = ""; }; CA44901E2463AD34003D8213 /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = ""; }; @@ -485,6 +487,7 @@ CAC281E1259FA44600B8AB0B /* Bundle+XcodesTests.swift */, CAC281E6259FA45A00B8AB0B /* Environment+Mock.swift */, CAD2E7B72449575100113D76 /* AppStateTests.swift */, + CA2518EB25A7FF2B00F08414 /* AppStateUpdateTests.swift */, CAD2E7B92449575100113D76 /* Info.plist */, ); path = XcodesTests; @@ -743,6 +746,7 @@ files = ( CAC281E7259FA45A00B8AB0B /* Environment+Mock.swift in Sources */, CAC281E2259FA44600B8AB0B /* Bundle+XcodesTests.swift in Sources */, + CA2518EC25A7FF2B00F08414 /* AppStateUpdateTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index f581fb4..b5b42d6 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -15,13 +15,21 @@ class AppState: ObservableObject { @Published var authenticationState: AuthenticationState = .unauthenticated @Published var availableXcodes: [AvailableXcode] = [] { willSet { - updateAllXcodes(availableXcodes: newValue, selectedXcodePath: selectedXcodePath) + updateAllXcodes( + availableXcodes: newValue, + installedXcodes: Current.files.installedXcodes(Path.root/"Applications"), + selectedXcodePath: selectedXcodePath + ) } } @Published var allXcodes: [Xcode] = [] @Published var selectedXcodePath: String? { willSet { - updateAllXcodes(availableXcodes: availableXcodes, selectedXcodePath: newValue) + updateAllXcodes( + availableXcodes: availableXcodes, + installedXcodes: Current.files.installedXcodes(Path.root/"Applications"), + selectedXcodePath: newValue + ) } } @Published var updatePublisher: AnyCancellable? @@ -335,11 +343,8 @@ class AppState: ObservableObject { NSPasteboard.general.writeObjects([installedXcode.path.url as NSURL]) NSPasteboard.general.setString(installedXcode.path.string, forType: .string) } - - // MARK: - Private - - private func updateAllXcodes(availableXcodes: [AvailableXcode], selectedXcodePath: String?) { - let installedXcodes = Current.files.installedXcodes(Path.root/"Applications") + + func updateAllXcodes(availableXcodes: [AvailableXcode], installedXcodes: [InstalledXcode], selectedXcodePath: String?) { var allXcodeVersions = availableXcodes.map { $0.version } for installedXcode in installedXcodes { // If an installed version isn't listed online, add the installed version @@ -362,9 +367,13 @@ class AppState: ObservableObject { .map { xcodeVersion in let installedXcode = installedXcodes.first(where: { xcodeVersion.isEquivalentForDeterminingIfInstalled(toInstalled: $0.version) }) let availableXcode = availableXcodes.first { $0.version == xcodeVersion } + let existingXcode = allXcodes.first { $0.version == xcodeVersion } + + let defaultInstallState: XcodeInstallState = installedXcode != nil ? .installed : .notInstalled + return Xcode( version: xcodeVersion, - installState: installedXcode != nil ? .installed : .notInstalled, + installState: existingXcode?.installState ?? defaultInstallState, selected: installedXcode != nil && selectedXcodePath?.hasPrefix(installedXcode!.path.string) == true, path: installedXcode?.path.string, icon: (installedXcode?.path.string).map(NSWorkspace.shared.icon(forFile:)), @@ -376,6 +385,7 @@ class AppState: ObservableObject { } } + // MARK: - Private private func uninstallXcode(path: Path) -> AnyPublisher { return Deferred { diff --git a/XcodesTests/AppStateUpdateTests.swift b/XcodesTests/AppStateUpdateTests.swift new file mode 100644 index 0000000..ee850bc --- /dev/null +++ b/XcodesTests/AppStateUpdateTests.swift @@ -0,0 +1,30 @@ +import Path +import Version +@testable import Xcodes +import XCTest + +class AppStateUpdateTests: XCTestCase { + var subject: AppState! + + override func setUpWithError() throws { + Current = .mock + subject = AppState() + } + + func testDoesNotReplaceInstallState() throws { + subject.allXcodes = [ + Xcode(version: Version("0.0.0")!, installState: .installing(.unarchiving), selected: false, path: nil, icon: nil) + ] + + subject.updateAllXcodes( + availableXcodes: [ + AvailableXcode(version: Version("0.0.0")!, url: URL(string: "https://apple.com/xcode.xip")!, filename: "mock.xip", releaseDate: nil) + ], + installedXcodes: [ + ], + selectedXcodePath: nil + ) + + XCTAssertEqual(subject.allXcodes[0].installState, .installing(.unarchiving)) + } +}