From 1ad79fa73f30f66a3c79ebb2db35bb86205d9e3d Mon Sep 17 00:00:00 2001 From: ohaiibuzzle <23693150+ohaiibuzzle@users.noreply.github.com> Date: Sun, 2 Jul 2023 00:16:31 +0700 Subject: [PATCH 1/2] feat: dialogs for GPTK update and uninstallation --- Harbor.xcodeproj/project.pbxproj | 4 + Harbor/Localizable.xcstrings | 78 ++++++++++++++- Harbor/Systems/GPKUtils.swift | 46 ++++++++- .../BottleManagement/GPTKConfigView.swift | 99 +++++++++++++++++++ Harbor/UIElements/Commands/HarborMenu.swift | 5 + Harbor/Utils/MenuUIStates.swift | 1 + Harbor/Views/BottleManagementView.swift | 3 + 7 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 Harbor/UIElements/BottleManagement/GPTKConfigView.swift diff --git a/Harbor.xcodeproj/project.pbxproj b/Harbor.xcodeproj/project.pbxproj index 4b42e77..c4c2081 100644 --- a/Harbor.xcodeproj/project.pbxproj +++ b/Harbor.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ AB7A81022A30D2FE00AA71A6 /* HarborUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB7A81012A30D2FE00AA71A6 /* HarborUtils.swift */; }; AB7D8E332A4DDE3400B55527 /* WinetricksUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB7D8E322A4DDE3400B55527 /* WinetricksUtils.swift */; }; AB87CAF42A4AC67C00C32025 /* HarborShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB87CAF32A4AC67C00C32025 /* HarborShortcuts.swift */; }; + AB95D9FD2A5011C5003402D2 /* GPTKConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB95D9FC2A5011C5003402D2 /* GPTKConfigView.swift */; }; ABC0BFCE2A31627400382A42 /* BottleManagementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC0BFCD2A31627400382A42 /* BottleManagementView.swift */; }; ABC0BFD12A31629300382A42 /* HarborBottle.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC0BFD02A31629300382A42 /* HarborBottle.swift */; }; ABC0BFD42A31691500382A42 /* BottleOpsDropdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC0BFD32A31691500382A42 /* BottleOpsDropdown.swift */; }; @@ -73,6 +74,7 @@ AB7A81012A30D2FE00AA71A6 /* HarborUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HarborUtils.swift; sourceTree = ""; }; AB7D8E322A4DDE3400B55527 /* WinetricksUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WinetricksUtils.swift; sourceTree = ""; }; AB87CAF32A4AC67C00C32025 /* HarborShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HarborShortcuts.swift; sourceTree = ""; }; + AB95D9FC2A5011C5003402D2 /* GPTKConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPTKConfigView.swift; sourceTree = ""; }; ABC0BFCD2A31627400382A42 /* BottleManagementView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottleManagementView.swift; sourceTree = ""; }; ABC0BFD02A31629300382A42 /* HarborBottle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HarborBottle.swift; sourceTree = ""; }; ABC0BFD32A31691500382A42 /* BottleOpsDropdown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottleOpsDropdown.swift; sourceTree = ""; }; @@ -228,6 +230,7 @@ AB6254332A3CE30D002A6206 /* BottleCardListView.swift */, AB0D004B2A40B8900019D62F /* DXVKInstallView.swift */, AB0D004D2A40E3D30019D62F /* EnvironmentVarsEditor.swift */, + AB95D9FC2A5011C5003402D2 /* GPTKConfigView.swift */, ); path = BottleManagement; sourceTree = ""; @@ -359,6 +362,7 @@ AB5CC6C02A308BBB00AEBB2B /* HarborApp.swift in Sources */, AB7D8E332A4DDE3400B55527 /* WinetricksUtils.swift in Sources */, AB7A81022A30D2FE00AA71A6 /* HarborUtils.swift in Sources */, + AB95D9FD2A5011C5003402D2 /* GPTKConfigView.swift in Sources */, ABF5340C2A3F63BE0030677A /* BottleManagementCardView.swift in Sources */, AB6652C42A3334E600F3FC5D /* XCLIUtils.swift in Sources */, AB6254342A3CE30D002A6206 /* BottleCardListView.swift in Sources */, diff --git a/Harbor/Localizable.xcstrings b/Harbor/Localizable.xcstrings index 96124bf..706984b 100644 --- a/Harbor/Localizable.xcstrings +++ b/Harbor/Localizable.xcstrings @@ -511,6 +511,17 @@ } } }, + "menu.harbor.reinstallGPTK" : { + "extractionState" : "stale", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reinstall GPTK" + } + } + } + }, "setup.btn.installGPK" : { "localizations" : { "en" : { @@ -592,6 +603,7 @@ } }, "setup.message.enterPassword" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1012,12 +1024,12 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "You can install GPTK quicker by obtaining a pre-built brew bottle of GPTK. \nThis saves your Mac from compiling Wine at the cost of potential compatibility issues.\nPlease note that this installation method excludes the shader compiler from Apple" + "value" : "You can install GPTK quicker by obtaining a pre-built brew bottle of GPTK. \nThis saves your Mac from compiling Wine at the cost of potential compatibility issues.\nPlease note that this installation method excludes the compiler from Apple" } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Możesz zainstalować GPK szybciej wybierając wcześniej skompilowaną butelkę Homebrew z GPTK.\nTo oszczędza twojego Maca od kompilowania Wine kosztem potencjalnych problemów z kompatybilnością\nTa metoda instalacji nie zawiera kompilatora shaderów od Apple" } } @@ -1135,6 +1147,66 @@ } } }, + "sheet.GPTKConfig.removeGPTK" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Completely remove GPTK" + } + } + } + }, + "sheet.GPTKConfig.removeGPTK.subtitle" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Harbor is about to completely remove GPTK from your device. You will need to reinstall it again if you want to use Harbor." + } + } + } + }, + "sheet.GPTKConfig.removeGPTK.title" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPTK Removal" + } + } + } + }, + "sheet.GPTKConfig.subtitle" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can update the GPTK DirectX libraries \nor completely remove GPTK for reinstallation when a newer release is available" + } + } + } + }, + "sheet.GPTKConfig.title" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configure GPTK" + } + } + } + }, + "sheet.GPTKConfig.updateGPTKLibs" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Update GPTK Libraries" + } + } + } + }, "sheet.HBInstall.status.installed" : { "localizations" : { "en" : { @@ -1457,4 +1529,4 @@ } }, "version" : "1.0" -} \ No newline at end of file +} diff --git a/Harbor/Systems/GPKUtils.swift b/Harbor/Systems/GPKUtils.swift index 8665045..c83ce06 100644 --- a/Harbor/Systems/GPKUtils.swift +++ b/Harbor/Systems/GPKUtils.swift @@ -106,9 +106,8 @@ final class GPKUtils { let aaplScript = """ property shellScript : "clear && \(brewUtils.x64BrewPrefix)/bin/brew install gstreamer pkg-config zlib \ freetype sdl2 libgphoto2 faudio jpeg libpng mpg123 libtiff libgsm glib gnutls libusb gettext molten-vk && \ + /usr/bin/xattr -r -d com.apple.quarantine \(gpkBottle.path) && \ \(brewUtils.x64BrewPrefix)/bin/brew install --ignore-dependencies \(gpkBottle.path) && \ - clear && echo '\(String(localized: "setup.message.enterPassword"))' && \ - sudo /usr/bin/xattr -r -d com.apple.quarantine /usr/local/opt/game-porting-toolkit/; \ clear && echo '\(String(localized: "setup.message.complete"))' && exit" tell application "Terminal" @@ -221,4 +220,47 @@ final class GPKUtils { return false } } + + func reinstallGPKLibraries() { + // Remove the GPK libraries + let gpkLib = URL(fileURLWithPath: "/usr/local/opt/game-porting-toolkit/lib/external") + if FileManager.default.fileExists(atPath: gpkLib.path) { + do { + try FileManager.default.removeItem(at: gpkLib) + } catch { + HarborUtils.shared.quickError(error.localizedDescription) + return + } + } + // Copy the GPK libraries + copyGPKLibraries() + } + + func completelyRemoveGPK() { + // Remove the GPK bottle from Brew + let aaplScript = """ + property shellScript : "/usr/local/Homebrew/bin/brew uninstall game-porting-toolkit" + + tell application "Terminal" + activate + -- Enter x86_64 shell + do script "arch -x86_64 /bin/sh" + delay 2 + -- Run removal + do script shellScript in front window + end tell + """ + + if let script = NSAppleScript(source: aaplScript) { + var error: NSDictionary? + script.executeAndReturnError(&error) + if let error = error { + NSLog("Harbor: Failed to execute AppleScript: \(error)") + } else { + status = .notInstalled + } + } else { + return + } + } } diff --git a/Harbor/UIElements/BottleManagement/GPTKConfigView.swift b/Harbor/UIElements/BottleManagement/GPTKConfigView.swift new file mode 100644 index 0000000..8645397 --- /dev/null +++ b/Harbor/UIElements/BottleManagement/GPTKConfigView.swift @@ -0,0 +1,99 @@ +// +// ReinstallGPTKView.swift +// Harbor +// +// Created by Venti on 01/07/2023. +// + +import SwiftUI + +struct GPTKConfigView: View { + @Binding var isPresented: Bool + @State var gpkSelected = false + @Environment(\.gpkUtils) var gpkUtils + + var body: some View { + VStack { + Text("sheet.GPTKConfig.title") + .font(.title) + .padding() + + Text("sheet.GPTKConfig.subtitle") + .multilineTextAlignment(.center) + + VStack(alignment: .center) { + HStack { + Button("btn.browse") { + let panel = NSOpenPanel() + panel.canChooseFiles = true + panel.canChooseDirectories = false + panel.allowsMultipleSelection = false + panel.allowedContentTypes = [.diskImage] + panel.begin { response in + if response == .OK { + let result = panel.url + if let result = result { + let destination = HarborUtils.shared.getContainerHome() + .appendingPathComponent("GPK.dmg") + do { + // Remove any existing GPK.dmg + if FileManager.default.fileExists(atPath: destination.path) { + try FileManager.default.removeItem(at: destination) + } + try FileManager.default.copyItem(at: result, to: destination) + gpkSelected = true + } catch { + NSLog("sheet.GPKInstall.status.failedCopy \(destination)") + } + } + } + } + } + if gpkSelected { + Text("sheet.GPKInstall.status.selected") + .foregroundColor(.green) + } + } + .padding() + + Button("sheet.GPTKConfig.updateGPTKLibs") { + gpkUtils.reinstallGPKLibraries() + isPresented.toggle() + } + .disabled(!gpkSelected) + + Button("sheet.GPTKConfig.removeGPTK") { + let alert = NSAlert() + alert.messageText = String(localized: "sheet.GPTKConfig.removeGPTK.title") + alert.informativeText = String(localized: "sheet.GPTKConfig.removeGPTK.subtitle") + alert.addButton(withTitle: String(localized: "home.btn.nuke")) + alert.addButton(withTitle: String(localized: "btn.cancel")) + alert.alertStyle = .warning + alert.runModal() == .alertFirstButtonReturn ? { + Task.detached { + gpkUtils.completelyRemoveGPK() + Task { @MainActor in + isPresented.toggle() + } + } + }() : () + } + .buttonStyle(.borderedProminent) + .tint(.red) + } + .padding() + Button("btn.OK") { + isPresented.toggle() + } + } + .padding() + } +} + +struct GPTKConfigView_Previews: PreviewProvider { + static var previews: some View { + GPTKConfigView(isPresented: Binding.constant(true)) + .environment(\.brewUtils, .init()) + .environment(\.gpkUtils, .init()) + } +} diff --git a/Harbor/UIElements/Commands/HarborMenu.swift b/Harbor/UIElements/Commands/HarborMenu.swift index 47736d2..5a0682b 100644 --- a/Harbor/UIElements/Commands/HarborMenu.swift +++ b/Harbor/UIElements/Commands/HarborMenu.swift @@ -11,6 +11,7 @@ struct HarborMenu: Commands { @Bindable var menuUIStates: MenuUIStates var body: some Commands { CommandGroup(after: .appVisibility) { + Divider() Button("menu.harbor.installDXVK") { menuUIStates.shouldShowDXVKSheet = true } @@ -18,6 +19,10 @@ struct HarborMenu: Commands { HarborUtils.shared.dropNukeOnWine() } .keyboardShortcut("k", modifiers: [.command, .option, .shift]) + Button("sheet.GPTKConfig.title") { + menuUIStates.shouldShowGPTKReinstallSheet = true + } + // Divider() } } } diff --git a/Harbor/Utils/MenuUIStates.swift b/Harbor/Utils/MenuUIStates.swift index 54beeb8..32e9cf5 100644 --- a/Harbor/Utils/MenuUIStates.swift +++ b/Harbor/Utils/MenuUIStates.swift @@ -13,4 +13,5 @@ final class MenuUIStates { // This class is for stuff that needs to be passed between // the menu items and the UI elements (eg. sheets within views) var shouldShowDXVKSheet = false + var shouldShowGPTKReinstallSheet = false } diff --git a/Harbor/Views/BottleManagementView.swift b/Harbor/Views/BottleManagementView.swift index 34021fd..dac3617 100644 --- a/Harbor/Views/BottleManagementView.swift +++ b/Harbor/Views/BottleManagementView.swift @@ -29,6 +29,9 @@ struct BottleManagementView: View { .sheet(isPresented: $menuUIStates.shouldShowDXVKSheet) { DXVKInstallView(isPresented: $menuUIStates.shouldShowDXVKSheet) } + .sheet(isPresented: $menuUIStates.shouldShowGPTKReinstallSheet) { + GPTKConfigView(isPresented: $menuUIStates.shouldShowGPTKReinstallSheet) + } } } From f8f434457b5d8675c8d15d4a16a5395986620b28 Mon Sep 17 00:00:00 2001 From: ohaiibuzzle <23693150+ohaiibuzzle@users.noreply.github.com> Date: Sun, 2 Jul 2023 00:43:33 +0700 Subject: [PATCH 2/2] fix: show prompt after uninstalling --- Harbor/Localizable.xcstrings | 24 +++--------------------- Harbor/Systems/GPKUtils.swift | 3 ++- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/Harbor/Localizable.xcstrings b/Harbor/Localizable.xcstrings index 706984b..3083c75 100644 --- a/Harbor/Localizable.xcstrings +++ b/Harbor/Localizable.xcstrings @@ -511,17 +511,6 @@ } } }, - "menu.harbor.reinstallGPTK" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Reinstall GPTK" - } - } - } - }, "setup.btn.installGPK" : { "localizations" : { "en" : { @@ -602,19 +591,12 @@ } } }, - "setup.message.enterPassword" : { - "extractionState" : "stale", + "setup.message.removalComplete" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Please enter your admin password in order to un-quarantine the newly installed bottle" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Wpisz hasło Administratora, aby usunąć kwarantannę z nowo zainstalowanej butelki" + "value" : "Game Porting Toolkit removal complete. You can now close this window" } } } @@ -1529,4 +1511,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/Harbor/Systems/GPKUtils.swift b/Harbor/Systems/GPKUtils.swift index c83ce06..3a0d30b 100644 --- a/Harbor/Systems/GPKUtils.swift +++ b/Harbor/Systems/GPKUtils.swift @@ -239,7 +239,8 @@ final class GPKUtils { func completelyRemoveGPK() { // Remove the GPK bottle from Brew let aaplScript = """ - property shellScript : "/usr/local/Homebrew/bin/brew uninstall game-porting-toolkit" + property shellScript : "/usr/local/Homebrew/bin/brew uninstall game-porting-toolkit && \ + echo '\(String(localized: "setup.message.removalComplete"))' && exit" tell application "Terminal" activate