mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-04-27 15:07:39 +00:00
add a unxip experiment for faster unxipping
This commit is contained in:
parent
c0974edc98
commit
ce001c8e68
13 changed files with 139 additions and 9 deletions
12
README.md
12
README.md
|
|
@ -18,6 +18,13 @@ _If you're looking for a command-line version of Xcodes.app, try [`xcodes`](http
|
||||||
- View release notes, OS compatibility, included SDKs and compilers from [Xcode Releases](https://xcodereleases.com).
|
- View release notes, OS compatibility, included SDKs and compilers from [Xcode Releases](https://xcodereleases.com).
|
||||||
- Dark/Light Mode supported
|
- Dark/Light Mode supported
|
||||||
|
|
||||||
|
## Experiments
|
||||||
|
|
||||||
|
- Thanks to the wonderful work of [https://github.com/saagarjha/unxip](https://github.com/saagarjha/unxip), turn on the experiment to increase your unxipping time by up to 70%! More can be found on his repo, but bugs, high memory may occur if used.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Xcodes.app runs on macOS Big Sur 11.0 or later.
|
Xcodes.app runs on macOS Big Sur 11.0 or later.
|
||||||
|
|
@ -80,7 +87,10 @@ scripts/package_release.sh
|
||||||
# Notarize the app
|
# Notarize the app
|
||||||
# Do this from the Product directory so the app is zipped without being nested inside Product
|
# Do this from the Product directory so the app is zipped without being nested inside Product
|
||||||
# Create a app specific password on appleid.apple.com if you haven't already
|
# Create a app specific password on appleid.apple.com if you haven't already
|
||||||
# % xcrun altool --store-password-in-keychain-item "AC_PASSWORD" -u "<appleiduseremail>" -p <app_specific_secret>
|
# xcrun notarytool store-credentials "AC_PASSWORD" \
|
||||||
|
# --apple-id "test@example.com" \
|
||||||
|
# --team-id "teamid" \
|
||||||
|
# --password "app specific password"
|
||||||
|
|
||||||
pushd Product
|
pushd Product
|
||||||
../scripts/notarize.sh "test@example.com" "@keychain:AC_PASSWORD" <MyOrg> Xcodes.zip
|
../scripts/notarize.sh "test@example.com" "@keychain:AC_PASSWORD" <MyOrg> Xcodes.zip
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87DD6EA25D053FA00D86808 /* Progress+.swift */; };
|
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87DD6EA25D053FA00D86808 /* Progress+.swift */; };
|
||||||
E89342FA25EDCC17007CF557 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89342F925EDCC17007CF557 /* NotificationManager.swift */; };
|
E89342FA25EDCC17007CF557 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89342F925EDCC17007CF557 /* NotificationManager.swift */; };
|
||||||
E8977EA325C11E1500835F80 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8977EA225C11E1500835F80 /* PreferencesView.swift */; };
|
E8977EA325C11E1500835F80 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8977EA225C11E1500835F80 /* PreferencesView.swift */; };
|
||||||
|
E8CBDB8727ADD92000B22292 /* unxip in Resources */ = {isa = PBXBuildFile; fileRef = E8CBDB8627ADD92000B22292 /* unxip */; };
|
||||||
|
E8CBDB8927ADE32300B22292 /* unxip in Copy aria2c */ = {isa = PBXBuildFile; fileRef = E8CBDB8627ADD92000B22292 /* unxip */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||||
|
E8CBDB8B27AE02FF00B22292 /* ExperiementsPreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8CBDB8A27AE02FF00B22292 /* ExperiementsPreferencePane.swift */; };
|
||||||
E8DA461125FAF7FB002E85EF /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8DA461025FAF7FB002E85EF /* NotificationsView.swift */; };
|
E8DA461125FAF7FB002E85EF /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8DA461025FAF7FB002E85EF /* NotificationsView.swift */; };
|
||||||
E8E98A9025D8631800EC89A0 /* InstallationStepRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBC3FF259AC17F00E2A3D8 /* InstallationStepRowView.swift */; };
|
E8E98A9025D8631800EC89A0 /* InstallationStepRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBC3FF259AC17F00E2A3D8 /* InstallationStepRowView.swift */; };
|
||||||
E8E98A9625D863D700EC89A0 /* InstallationStepDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */; };
|
E8E98A9625D863D700EC89A0 /* InstallationStepDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */; };
|
||||||
|
|
@ -153,6 +156,7 @@
|
||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 6;
|
dstSubfolderSpec = 6;
|
||||||
files = (
|
files = (
|
||||||
|
E8CBDB8927ADE32300B22292 /* unxip in Copy aria2c */,
|
||||||
CAA8589325A2B77E00ACF8C0 /* aria2c in Copy aria2c */,
|
CAA8589325A2B77E00ACF8C0 /* aria2c in Copy aria2c */,
|
||||||
);
|
);
|
||||||
name = "Copy aria2c";
|
name = "Copy aria2c";
|
||||||
|
|
@ -272,6 +276,8 @@
|
||||||
E87DD6EA25D053FA00D86808 /* Progress+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+.swift"; sourceTree = "<group>"; };
|
E87DD6EA25D053FA00D86808 /* Progress+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+.swift"; sourceTree = "<group>"; };
|
||||||
E89342F925EDCC17007CF557 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
E89342F925EDCC17007CF557 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
||||||
E8977EA225C11E1500835F80 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
E8977EA225C11E1500835F80 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
||||||
|
E8CBDB8627ADD92000B22292 /* unxip */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = unxip; sourceTree = "<group>"; };
|
||||||
|
E8CBDB8A27AE02FF00B22292 /* ExperiementsPreferencePane.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperiementsPreferencePane.swift; sourceTree = "<group>"; };
|
||||||
E8DA461025FAF7FB002E85EF /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
|
E8DA461025FAF7FB002E85EF /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
|
||||||
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStepDetailView.swift; sourceTree = "<group>"; };
|
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStepDetailView.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
@ -484,6 +490,7 @@
|
||||||
CA9FF83E2594FBC000E47BAF /* Licenses.rtf */,
|
CA9FF83E2594FBC000E47BAF /* Licenses.rtf */,
|
||||||
CAD2E7AE2449575000113D76 /* Xcodes.entitlements */,
|
CAD2E7AE2449575000113D76 /* Xcodes.entitlements */,
|
||||||
CA8FB64D256E17B100469DA5 /* XcodesTest.entitlements */,
|
CA8FB64D256E17B100469DA5 /* XcodesTest.entitlements */,
|
||||||
|
E8CBDB8627ADD92000B22292 /* unxip */,
|
||||||
);
|
);
|
||||||
path = Resources;
|
path = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -561,6 +568,7 @@
|
||||||
CAFE4ABB25B7D54B0064FE51 /* UpdatesPreferencePane.swift */,
|
CAFE4ABB25B7D54B0064FE51 /* UpdatesPreferencePane.swift */,
|
||||||
E8977EA225C11E1500835F80 /* PreferencesView.swift */,
|
E8977EA225C11E1500835F80 /* PreferencesView.swift */,
|
||||||
E8DA461025FAF7FB002E85EF /* NotificationsView.swift */,
|
E8DA461025FAF7FB002E85EF /* NotificationsView.swift */,
|
||||||
|
E8CBDB8A27AE02FF00B22292 /* ExperiementsPreferencePane.swift */,
|
||||||
);
|
);
|
||||||
path = Preferences;
|
path = Preferences;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -707,6 +715,7 @@
|
||||||
files = (
|
files = (
|
||||||
CAD2E7A92449575000113D76 /* Preview Assets.xcassets in Resources */,
|
CAD2E7A92449575000113D76 /* Preview Assets.xcassets in Resources */,
|
||||||
CA9FF83F2594FBC000E47BAF /* Licenses.rtf in Resources */,
|
CA9FF83F2594FBC000E47BAF /* Licenses.rtf in Resources */,
|
||||||
|
E8CBDB8727ADD92000B22292 /* unxip in Resources */,
|
||||||
CAA858DB25A3E11F00ACF8C0 /* aria2-release-1.35.0.tar.gz in Resources */,
|
CAA858DB25A3E11F00ACF8C0 /* aria2-release-1.35.0.tar.gz in Resources */,
|
||||||
CAD2E7A62449575000113D76 /* Assets.xcassets in Resources */,
|
CAD2E7A62449575000113D76 /* Assets.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
|
|
@ -785,6 +794,7 @@
|
||||||
CABFA9BD2592EEEA00380FEE /* Environment.swift in Sources */,
|
CABFA9BD2592EEEA00380FEE /* Environment.swift in Sources */,
|
||||||
CABFA9C32592EEEA00380FEE /* Downloads.swift in Sources */,
|
CABFA9C32592EEEA00380FEE /* Downloads.swift in Sources */,
|
||||||
CAC281DA259F985100B8AB0B /* InstallationStep.swift in Sources */,
|
CAC281DA259F985100B8AB0B /* InstallationStep.swift in Sources */,
|
||||||
|
E8CBDB8B27AE02FF00B22292 /* ExperiementsPreferencePane.swift in Sources */,
|
||||||
E8E98A9625D863D700EC89A0 /* InstallationStepDetailView.swift in Sources */,
|
E8E98A9625D863D700EC89A0 /* InstallationStepDetailView.swift in Sources */,
|
||||||
CA378F992466567600A58CE0 /* AppState.swift in Sources */,
|
CA378F992466567600A58CE0 /* AppState.swift in Sources */,
|
||||||
CAD2E7A42449574E00113D76 /* XcodeListView.swift in Sources */,
|
CAD2E7A42449574E00113D76 /* XcodeListView.swift in Sources */,
|
||||||
|
|
|
||||||
7
Xcodes/AcknowledgementsGenerator/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
Xcodes/AcknowledgementsGenerator/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
|
|
@ -238,8 +238,8 @@ extension AppState {
|
||||||
|
|
||||||
func unarchiveAndMoveXIP(availableXcode: AvailableXcode, at source: URL, to destination: URL) -> AnyPublisher<URL, Swift.Error> {
|
func unarchiveAndMoveXIP(availableXcode: AvailableXcode, at source: URL, to destination: URL) -> AnyPublisher<URL, Swift.Error> {
|
||||||
self.setInstallationStep(of: availableXcode.version, to: .unarchiving)
|
self.setInstallationStep(of: availableXcode.version, to: .unarchiving)
|
||||||
|
|
||||||
return Current.shell.unxip(source)
|
return unxipOrUnxipExperiment(source)
|
||||||
.catch { error -> AnyPublisher<ProcessOutput, Swift.Error> in
|
.catch { error -> AnyPublisher<ProcessOutput, Swift.Error> in
|
||||||
if let executionError = error as? ProcessExecutionError {
|
if let executionError = error as? ProcessExecutionError {
|
||||||
if executionError.standardError.contains("damaged and can’t be expanded") {
|
if executionError.standardError.contains("damaged and can’t be expanded") {
|
||||||
|
|
@ -278,6 +278,16 @@ extension AppState {
|
||||||
})
|
})
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unxipOrUnxipExperiment(_ source: URL) -> AnyPublisher<ProcessOutput, Error> {
|
||||||
|
if unxipExperiment {
|
||||||
|
// All hard work done by https://github.com/saagarjha/unxip
|
||||||
|
// Compiled to binary with `swiftc -parse-as-library -O unxip.swift`
|
||||||
|
return Current.shell.unxipExperiment(source)
|
||||||
|
} else {
|
||||||
|
return Current.shell.unxip(source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func verifySecurityAssessment(of xcode: InstalledXcode) -> AnyPublisher<Void, Error> {
|
public func verifySecurityAssessment(of xcode: InstalledXcode) -> AnyPublisher<Void, Error> {
|
||||||
return Current.shell.spctlAssess(xcode.path.url)
|
return Current.shell.spctlAssess(xcode.path.url)
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,12 @@ class AppState: ObservableObject {
|
||||||
Current.defaults.set(localPath, forKey: "localPath")
|
Current.defaults.set(localPath, forKey: "localPath")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Published var unxipExperiment = false {
|
||||||
|
didSet {
|
||||||
|
Current.defaults.set(unxipExperiment, forKey: "unxipExperiment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Publisher Cancellables
|
// MARK: - Publisher Cancellables
|
||||||
|
|
||||||
|
|
@ -96,6 +102,7 @@ class AppState: ObservableObject {
|
||||||
|
|
||||||
func setupDefaults() {
|
func setupDefaults() {
|
||||||
localPath = Current.defaults.string(forKey: "localPath") ?? Path.defaultXcodesApplicationSupport.string
|
localPath = Current.defaults.string(forKey: "localPath") ?? Path.defaultXcodesApplicationSupport.string
|
||||||
|
unxipExperiment = Current.defaults.bool(forKey: "unxipExperiment") ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Timer
|
// MARK: Timer
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,12 @@ public struct Shell {
|
||||||
|
|
||||||
return (progress, publisher)
|
return (progress, publisher)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var unxipExperiment: (URL) -> AnyPublisher<ProcessOutput, Error> = { url in
|
||||||
|
let unxipPath = Path(url: Bundle.main.url(forAuxiliaryExecutable: "unxip")!)!
|
||||||
|
return Process.run(unxipPath.url, workingDirectory: url.deletingLastPathComponent(), ["\(url.path)"])
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Files {
|
public struct Files {
|
||||||
|
|
@ -238,6 +244,11 @@ public struct Defaults {
|
||||||
public func get(forKey key: String) -> Any? {
|
public func get(forKey key: String) -> Any? {
|
||||||
get(key)
|
get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var bool: (String) -> Bool? = { UserDefaults.standard.bool(forKey: $0) }
|
||||||
|
public func bool(forKey key: String) -> Bool? {
|
||||||
|
bool(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let helperClient = HelperClient()
|
private let helperClient = HelperClient()
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,6 @@ struct AboutView: View {
|
||||||
|
|
||||||
Text("Version \(Bundle.main.shortVersion!) (\(Bundle.main.version!))")
|
Text("Version \(Bundle.main.shortVersion!) (\(Bundle.main.version!))")
|
||||||
|
|
||||||
Color.clear
|
|
||||||
.frame(width: 300, height: 16)
|
|
||||||
|
|
||||||
HStack(spacing: 32) {
|
HStack(spacing: 32) {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
openURL(URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")!)
|
openURL(URL(string: "https://github.com/RobotsAndPencils/XcodesApp/")!)
|
||||||
|
|
@ -30,6 +27,24 @@ struct AboutView: View {
|
||||||
}
|
}
|
||||||
.buttonStyle(LinkButtonStyle())
|
.buttonStyle(LinkButtonStyle())
|
||||||
}
|
}
|
||||||
|
Color.clear
|
||||||
|
.frame(width: 300, height: 0)
|
||||||
|
Label("Unxip Experiment", systemImage: "testtube.2")
|
||||||
|
HStack(spacing: 32) {
|
||||||
|
Button(action: {
|
||||||
|
openURL(URL(string: "https://github.com/saagarjha/unxip/")!)
|
||||||
|
}) {
|
||||||
|
Label("Github Repo", systemImage: "link")
|
||||||
|
}
|
||||||
|
.buttonStyle(LinkButtonStyle())
|
||||||
|
|
||||||
|
Button(action: {
|
||||||
|
openURL(URL(string: "https://github.com/saagarjha/unxip/blob/main/LICENSE")!)
|
||||||
|
}) {
|
||||||
|
Label("License", systemImage: "link")
|
||||||
|
}
|
||||||
|
.buttonStyle(LinkButtonStyle())
|
||||||
|
}
|
||||||
|
|
||||||
Text(Bundle.main.humanReadableCopyright!)
|
Text(Bundle.main.humanReadableCopyright!)
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
|
|
|
||||||
55
Xcodes/Frontend/Preferences/ExperiementsPreferencePane.swift
Normal file
55
Xcodes/Frontend/Preferences/ExperiementsPreferencePane.swift
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import AppleAPI
|
||||||
|
import SwiftUI
|
||||||
|
import Path
|
||||||
|
|
||||||
|
struct ExperimentsPreferencePane: View {
|
||||||
|
@EnvironmentObject var appState: AppState
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
|
GroupBox(label: Text("Faster Unxip")) {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Toggle(
|
||||||
|
"When unxipping, use experiment",
|
||||||
|
isOn: $appState.unxipExperiment
|
||||||
|
)
|
||||||
|
AttributedText(unxipFootnote)
|
||||||
|
}
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
}
|
||||||
|
.groupBoxStyle(PreferencesGroupBoxStyle())
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
.frame(width: 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var unxipFootnote: NSAttributedString {
|
||||||
|
let string = """
|
||||||
|
Thanks to @_saagarjha, this experiment can increase unxipping
|
||||||
|
speed by up to 70% for some systems.
|
||||||
|
|
||||||
|
More information on how this is accomplished can be seen
|
||||||
|
on the unxip repo - https://github.com/saagarjha/unxip
|
||||||
|
"""
|
||||||
|
let attributedString = NSMutableAttributedString(
|
||||||
|
string: string,
|
||||||
|
attributes: [
|
||||||
|
.font: NSFont.preferredFont(forTextStyle: .footnote, options: [:]),
|
||||||
|
.foregroundColor: NSColor.labelColor
|
||||||
|
]
|
||||||
|
)
|
||||||
|
attributedString.addAttribute(.link, value: URL(string: "https://twitter.com/_saagarjha")!, range: NSRange(string.range(of: "@_saagarjha")!, in: string))
|
||||||
|
attributedString.addAttribute(.link, value: URL(string: "https://github.com/saagarjha/unxip")!, range: NSRange(string.range(of: "https://github.com/saagarjha/unxip")!, in: string))
|
||||||
|
return attributedString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ExperimentsPreferencePane_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
Group {
|
||||||
|
ExperimentsPreferencePane()
|
||||||
|
.environmentObject(AppState())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import SwiftUI
|
||||||
|
|
||||||
struct PreferencesView: View {
|
struct PreferencesView: View {
|
||||||
private enum Tabs: Hashable {
|
private enum Tabs: Hashable {
|
||||||
case general, updates, advanced
|
case general, updates, advanced, experiment
|
||||||
}
|
}
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
|
|
||||||
|
|
@ -25,6 +25,11 @@ struct PreferencesView: View {
|
||||||
Label("Advanced", systemImage: "gearshape.2")
|
Label("Advanced", systemImage: "gearshape.2")
|
||||||
}
|
}
|
||||||
.tag(Tabs.advanced)
|
.tag(Tabs.advanced)
|
||||||
|
ExperimentsPreferencePane()
|
||||||
|
.tabItem {
|
||||||
|
Label("Experiments", systemImage: "testtube.2")
|
||||||
|
}
|
||||||
|
.tag(Tabs.experiment)
|
||||||
}
|
}
|
||||||
.padding(20)
|
.padding(20)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Copyright © 2020 Robots and Pencils.</string>
|
<string>Copyright © 2022 Robots and Pencils.</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSSupportsAutomaticTermination</key>
|
<key>NSSupportsAutomaticTermination</key>
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
<key>SMPrivilegedExecutables</key>
|
<key>SMPrivilegedExecutables</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.robotsandpencils.XcodesApp.Helper</key>
|
<key>com.robotsandpencils.XcodesApp.Helper</key>
|
||||||
<string>identifier "com.robotsandpencils.XcodesApp.Helper" and info [CFBundleShortVersionString] >= "1.0.0" and anchor apple generic and certificate leaf[subject.OU] = "$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)"</string>
|
<string>identifier "com.robotsandpencils.XcodesApp.Helper" and info [CFBundleShortVersionString] >= "1.0.0" and anchor apple generic and certificate leaf[subject.OU] = "$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)"</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SUFeedURL</key>
|
<key>SUFeedURL</key>
|
||||||
<string>https://robotsandpencils.github.io/XcodesApp/appcast.xml</string>
|
<string>https://robotsandpencils.github.io/XcodesApp/appcast.xml</string>
|
||||||
|
|
|
||||||
BIN
Xcodes/Resources/unxip
Executable file
BIN
Xcodes/Resources/unxip
Executable file
Binary file not shown.
BIN
experiment_dark.jpg
Normal file
BIN
experiment_dark.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
BIN
experiment_light.jpg
Normal file
BIN
experiment_light.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Loading…
Reference in a new issue