mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-04-25 14:47:38 +00:00
Uninstall a xcode version
This commit is contained in:
parent
38756100b7
commit
7bfb94d75a
5 changed files with 117 additions and 23 deletions
|
|
@ -12,6 +12,7 @@ class AppState: ObservableObject {
|
||||||
private let helperClient = HelperClient()
|
private let helperClient = HelperClient()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
private var selectPublisher: AnyCancellable?
|
private var selectPublisher: AnyCancellable?
|
||||||
|
private var uninstallPublisher: AnyCancellable?
|
||||||
|
|
||||||
@Published var authenticationState: AuthenticationState = .unauthenticated
|
@Published var authenticationState: AuthenticationState = .unauthenticated
|
||||||
@Published var availableXcodes: [AvailableXcode] = [] {
|
@Published var availableXcodes: [AvailableXcode] = [] {
|
||||||
|
|
@ -32,7 +33,6 @@ class AppState: ObservableObject {
|
||||||
@Published var presentingSignInAlert = false
|
@Published var presentingSignInAlert = false
|
||||||
@Published var isProcessingAuthRequest = false
|
@Published var isProcessingAuthRequest = false
|
||||||
@Published var secondFactorData: SecondFactorData?
|
@Published var secondFactorData: SecondFactorData?
|
||||||
@Published var xcodeBeingConfirmedForUninstallation: Xcode?
|
|
||||||
@Published var helperInstallState: HelperInstallState = .notInstalled
|
@Published var helperInstallState: HelperInstallState = .notInstalled
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
|
@ -200,14 +200,36 @@ class AppState: ObservableObject {
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: - Install
|
||||||
|
|
||||||
func install(id: Xcode.ID) {
|
func install(id: Xcode.ID) {
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Uninstall
|
||||||
func uninstall(id: Xcode.ID) {
|
func uninstall(id: Xcode.ID) {
|
||||||
// TODO:
|
if helperInstallState == .notInstalled {
|
||||||
|
installHelper()
|
||||||
|
}
|
||||||
|
|
||||||
|
guard
|
||||||
|
let installedXcode = Current.files.installedXcodes(Path.root/"Applications").first(where: { $0.version == id }),
|
||||||
|
uninstallPublisher == nil
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
uninstallPublisher = HelperClient().uninstallXcode(installedXcode.path)
|
||||||
|
.flatMap { [unowned self] _ in
|
||||||
|
self.updateSelectedXcodePath()
|
||||||
|
}
|
||||||
|
.sink(
|
||||||
|
receiveCompletion: { [unowned self] completion in
|
||||||
|
if case let .failure(error) = completion {
|
||||||
|
self.error = AlertContent(title: "Error uninstalling Xcode", message: error.legibleLocalizedDescription)
|
||||||
|
}
|
||||||
|
self.uninstallPublisher = nil
|
||||||
|
},
|
||||||
|
receiveValue: { _ in }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reveal(id: Xcode.ID) {
|
func reveal(id: Xcode.ID) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Path
|
||||||
|
|
||||||
final class HelperClient {
|
final class HelperClient {
|
||||||
private var connection: NSXPCConnection?
|
private var connection: NSXPCConnection?
|
||||||
|
|
@ -103,4 +104,27 @@ final class HelperClient {
|
||||||
.map { $0.0 }
|
.map { $0.0 }
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uninstallXcode(_ path: Path) -> AnyPublisher<Void, Error> {
|
||||||
|
let connectionErrorSubject = PassthroughSubject<String, Error>()
|
||||||
|
|
||||||
|
return Deferred {
|
||||||
|
Future { promise in
|
||||||
|
do {
|
||||||
|
try Current.files.trashItem(at: path.url)
|
||||||
|
promise(.success(()))
|
||||||
|
} catch {
|
||||||
|
promise(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Take values, but fail when connectionErrorSubject fails
|
||||||
|
.zip(
|
||||||
|
connectionErrorSubject
|
||||||
|
.prepend("")
|
||||||
|
.map { _ in Void() }
|
||||||
|
)
|
||||||
|
.map { $0.0 }
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ struct XcodeCommands: Commands {
|
||||||
var body: some Commands {
|
var body: some Commands {
|
||||||
CommandMenu("Xcode") {
|
CommandMenu("Xcode") {
|
||||||
Group {
|
Group {
|
||||||
|
|
||||||
InstallCommand()
|
InstallCommand()
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
@ -17,6 +18,7 @@ struct XcodeCommands: Commands {
|
||||||
OpenCommand()
|
OpenCommand()
|
||||||
RevealCommand()
|
RevealCommand()
|
||||||
CopyPathCommand()
|
CopyPathCommand()
|
||||||
|
UninstallCommand()
|
||||||
}
|
}
|
||||||
.environmentObject(appState)
|
.environmentObject(appState)
|
||||||
}
|
}
|
||||||
|
|
@ -31,24 +33,15 @@ struct InstallButton: View {
|
||||||
let xcode: Xcode?
|
let xcode: Xcode?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button(action: uninstallOrInstall) {
|
Button(action: install) {
|
||||||
if let xcode = xcode {
|
Text("Install")
|
||||||
Text(xcode.installed == true ? "Uninstall" : "Install")
|
.help("Install")
|
||||||
.help(xcode.installed == true ? "Uninstall" : "Install")
|
|
||||||
} else {
|
|
||||||
Text("Install")
|
|
||||||
.help("Install")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func uninstallOrInstall() {
|
private func install() {
|
||||||
guard let xcode = xcode else { return }
|
guard let xcode = xcode else { return }
|
||||||
if xcode.installed {
|
appState.install(id: xcode.id)
|
||||||
appState.xcodeBeingConfirmedForUninstallation = xcode
|
|
||||||
} else {
|
|
||||||
appState.install(id: xcode.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,6 +84,30 @@ struct OpenButton: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UninstallButton: View {
|
||||||
|
@EnvironmentObject var appState: AppState
|
||||||
|
let xcode: Xcode?
|
||||||
|
|
||||||
|
@State private var showingAlert = false
|
||||||
|
var alert: Alert {
|
||||||
|
Alert(title: Text("Uninstall Xcode \(xcode!.description)?"),
|
||||||
|
message: Text("It will be moved to the Trash, but won't be emptied."),
|
||||||
|
primaryButton: .destructive(Text("Uninstall"), action: { self.appState.uninstall(id: xcode!.id) }),
|
||||||
|
secondaryButton: .cancel(Text("Cancel")))
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: {
|
||||||
|
self.showingAlert = true
|
||||||
|
}) {
|
||||||
|
Text("Uninstall")
|
||||||
|
}
|
||||||
|
.foregroundColor(.red)
|
||||||
|
.help("Uninstall")
|
||||||
|
.alert(isPresented:$showingAlert, content: { self.alert })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct RevealButton: View {
|
struct RevealButton: View {
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
let xcode: Xcode?
|
let xcode: Xcode?
|
||||||
|
|
@ -133,8 +150,8 @@ struct InstallCommand: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
InstallButton(xcode: selectedXcode.unwrapped)
|
InstallButton(xcode: selectedXcode.unwrapped)
|
||||||
.keyboardShortcut(selectedXcode.unwrapped?.installed == true ? "u" : "i", modifiers: [.command, .option])
|
.keyboardShortcut("i", modifiers: [.command, .option])
|
||||||
.disabled(selectedXcode.unwrapped == nil)
|
.disabled(selectedXcode.unwrapped?.installed == true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,3 +198,14 @@ struct CopyPathCommand: View {
|
||||||
.disabled(selectedXcode.unwrapped?.installed != true)
|
.disabled(selectedXcode.unwrapped?.installed != true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UninstallCommand: View {
|
||||||
|
@EnvironmentObject var appState: AppState
|
||||||
|
@FocusedValue(\.selectedXcode) private var selectedXcode: SelectedXcode?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
UninstallButton(xcode: selectedXcode.unwrapped)
|
||||||
|
.keyboardShortcut("u", modifiers: [.command, .option])
|
||||||
|
.disabled(selectedXcode.unwrapped?.installed != true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,11 @@ struct InfoPane: View {
|
||||||
sdks(for: xcode)
|
sdks(for: xcode)
|
||||||
compilers(for: xcode)
|
compilers(for: xcode)
|
||||||
|
|
||||||
|
if xcode.path != nil {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
UninstallButton(xcode: xcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -250,6 +255,21 @@ struct InfoPane_Previews: PreviewProvider {
|
||||||
})
|
})
|
||||||
.previewDisplayName("Populated, Uninstalled")
|
.previewDisplayName("Populated, Uninstalled")
|
||||||
|
|
||||||
|
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
|
||||||
|
.environmentObject(configure(AppState()) {
|
||||||
|
$0.allXcodes = [
|
||||||
|
.init(
|
||||||
|
version: Version(major: 12, minor: 3, patch: 0),
|
||||||
|
installState: .installed,
|
||||||
|
selected: false,
|
||||||
|
path: "/Applications/Xcode-12.3.0.app",
|
||||||
|
icon: nil,
|
||||||
|
sdks: nil,
|
||||||
|
compilers: nil)
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.previewDisplayName("Basic, installed")
|
||||||
|
|
||||||
InfoPane(selectedXcodeID: nil)
|
InfoPane(selectedXcodeID: nil)
|
||||||
.environmentObject(configure(AppState()) {
|
.environmentObject(configure(AppState()) {
|
||||||
$0.allXcodes = [
|
$0.allXcodes = [
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,15 @@ struct XcodeListViewRow: View {
|
||||||
installControl(for: xcode)
|
installControl(for: xcode)
|
||||||
}
|
}
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
InstallButton(xcode: xcode)
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
|
|
||||||
if xcode.installed {
|
if xcode.installed {
|
||||||
SelectButton(xcode: xcode)
|
SelectButton(xcode: xcode)
|
||||||
OpenButton(xcode: xcode)
|
OpenButton(xcode: xcode)
|
||||||
RevealButton(xcode: xcode)
|
RevealButton(xcode: xcode)
|
||||||
CopyPathButton(xcode: xcode)
|
CopyPathButton(xcode: xcode)
|
||||||
|
Divider()
|
||||||
|
UninstallButton(xcode: xcode)
|
||||||
|
} else {
|
||||||
|
InstallButton(xcode: xcode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue