Compare commits
26 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a0d3353b9 | ||
|
|
da8d22c6d3 | ||
|
|
4f9b7f8f6a | ||
|
|
f34e291433 | ||
|
|
789eedcdb7 | ||
|
|
f9262d9a05 | ||
|
|
4776af75ee | ||
|
|
cab5533b49 | ||
|
|
fc50db1cee | ||
|
|
576585b7de | ||
|
|
6cf9647840 | ||
|
|
90dccd8180 | ||
|
|
372d5b1f4e | ||
|
|
4063796833 | ||
|
|
be2eea0532 | ||
|
|
a6dec75603 | ||
|
|
9527fb2961 | ||
|
|
084bd8f4a1 | ||
|
|
f93da1c502 | ||
|
|
79ef494504 | ||
|
|
cdf3675a5e | ||
|
|
5974a85800 | ||
|
|
4ccb6e7f06 | ||
|
|
22e4991f9a | ||
|
|
059c51b5dd | ||
|
|
bbec397613 |
BIN
IconDark.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
IconMono.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
13
README.md
|
|
@ -1,4 +1,4 @@
|
||||||
<h1><img src="icon.png" align="center" width=50 height=50 /> Xcodes.app</h1>
|
<h1><img src="icon.png" align="center" width=50 height=50 /> <img src="IconDark.png" align="center" width=50 height=50 /> <img src="IconMono.png" align="center" width=50 height=50 /> Xcodes.app</h1>
|
||||||
|
|
||||||
The easiest way to install and switch between multiple versions of Xcode.
|
The easiest way to install and switch between multiple versions of Xcode.
|
||||||
|
|
||||||
|
|
@ -23,6 +23,8 @@ XcodesApp is now part of the `XcodesOrg` - [read more here](nextstep.md)
|
||||||
- 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
|
||||||
- Security Key Authentication supported
|
- Security Key Authentication supported
|
||||||
|
- Support installing Platforms/Runtimes
|
||||||
|
- Support installing Apple Silicon variants
|
||||||
|
|
||||||
## Platforms/Runtimes
|
## Platforms/Runtimes
|
||||||
|
|
||||||
|
|
@ -30,6 +32,10 @@ XcodesApp is now part of the `XcodesOrg` - [read more here](nextstep.md)
|
||||||
|
|
||||||
**Note: iOS 18+, tvOS 18+, watchOS 11+, visionOS 2+ requires that Xcode 16.1 Beta 3+ be installed and active.**
|
**Note: iOS 18+, tvOS 18+, watchOS 11+, visionOS 2+ requires that Xcode 16.1 Beta 3+ be installed and active.**
|
||||||
|
|
||||||
|
## Apple Silicon Variants
|
||||||
|
|
||||||
|
As of Xcode 26, Apple provides Apple Silicon as well as Universal variants for Xcode versions as well as each runtime. Simply tap on which variant you want installed. To install the Apple Silicon runtime variant Xcode 26 is required to be active.
|
||||||
|
|
||||||
## Experiments
|
## 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.
|
- 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.
|
||||||
|
|
@ -54,12 +60,14 @@ The following languages are supported because of the following community users!
|
||||||
|German 🇩🇪|[@drct](https://github.com/drct)|Dutch 🇳🇱|[@jfversluis](https://github/com/jfversluis)|
|
|German 🇩🇪|[@drct](https://github.com/drct)|Dutch 🇳🇱|[@jfversluis](https://github/com/jfversluis)|
|
||||||
|Brazilian Portuguese 🇧🇷|[@brunomunizaf](https://github.com/brunomunizaf)|Polish 🇵🇱|[@jakex7](https://github.com/jakex7)|
|
|Brazilian Portuguese 🇧🇷|[@brunomunizaf](https://github.com/brunomunizaf)|Polish 🇵🇱|[@jakex7](https://github.com/jakex7)|
|
||||||
|Catalan|[@ferranabello](https://github.com/ferranabello)|Greek 🇬🇷|[@alladinian](https://github.com/alladinian)
|
|Catalan|[@ferranabello](https://github.com/ferranabello)|Greek 🇬🇷|[@alladinian](https://github.com/alladinian)
|
||||||
|
|Thai 🇹🇭|[@neetrath](https://github.com/neetrath)|
|
||||||
|
|
||||||
Want to add more languages? Simply create a PR with the updated strings file.
|
Want to add more languages? Simply create a PR with the updated strings file.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
v1.X - requires macOS 11 or newer
|
v1.X - requires macOS 11 or newer
|
||||||
v2.X - requires macOS 13
|
v2.X - requires macOS 13
|
||||||
|
v3.X - requires macOS 13 - architecture variants and updated icon.
|
||||||
|
|
||||||
### Install with Homebrew
|
### Install with Homebrew
|
||||||
|
|
||||||
|
|
@ -84,7 +92,7 @@ Xcodes.app and CLI is updated, maintained with contributors like yourself. Even
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
You'll need macOS 13.5 Ventura and Xcode 15 in order to build and run Xcodes.app.
|
You'll need macOS 15.6 Ventura and Xcode 26 in order to build and run Xcodes.app.
|
||||||
|
|
||||||
`Unxip` and `aria2` must be compiled as a universal binary
|
`Unxip` and `aria2` must be compiled as a universal binary
|
||||||
```
|
```
|
||||||
|
|
@ -99,7 +107,6 @@ You'll need macOS 13.5 Ventura and Xcode 15 in order to build and run Xcodes.app
|
||||||
lipo -archs unxip
|
lipo -archs unxip
|
||||||
```
|
```
|
||||||
|
|
||||||
Notable design decisions are recorded in [DECISIONS.md](./DECISIONS.md). The Apple authentication flow is described in [Apple.paw](./Apple.paw), which will allow you to play with the API endpoints that are involved using the [Paw](https://paw.cloud) app.
|
|
||||||
|
|
||||||
[`xcode-install`](https://github.com/xcpretty/xcode-install) and [fastlane/spaceship](https://github.com/fastlane/fastlane/tree/master/spaceship) both deserve credit for figuring out the hard parts of what makes this possible.
|
[`xcode-install`](https://github.com/xcpretty/xcode-install) and [fastlane/spaceship](https://github.com/fastlane/fastlane/tree/master/spaceship) both deserve credit for figuring out the hard parts of what makes this possible.
|
||||||
|
|
||||||
|
|
|
||||||
26
Scripts/fix_libfido2_framework.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Fix libfido2.framework structure for macOS validation
|
||||||
|
# If this script is not run, the build will fail because xcodebuild is expecting the library in a specific structure
|
||||||
|
FRAMEWORK_PATH="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Contents/Frameworks/libfido2.framework"
|
||||||
|
|
||||||
|
if [ -d "$FRAMEWORK_PATH" ] && [ -f "$FRAMEWORK_PATH/Info.plist" ] && [ ! -d "$FRAMEWORK_PATH/Versions" ]; then
|
||||||
|
echo "Fixing libfido2.framework bundle structure..."
|
||||||
|
|
||||||
|
# Create proper bundle structure
|
||||||
|
mkdir -p "$FRAMEWORK_PATH/Versions/A/Resources"
|
||||||
|
|
||||||
|
# Move files to proper locations
|
||||||
|
mv "$FRAMEWORK_PATH/Info.plist" "$FRAMEWORK_PATH/Versions/A/Resources/"
|
||||||
|
mv "$FRAMEWORK_PATH/libfido2" "$FRAMEWORK_PATH/Versions/A/"
|
||||||
|
if [ -f "$FRAMEWORK_PATH/LICENSE" ]; then
|
||||||
|
mv "$FRAMEWORK_PATH/LICENSE" "$FRAMEWORK_PATH/Versions/A/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create symbolic links
|
||||||
|
ln -sf A "$FRAMEWORK_PATH/Versions/Current"
|
||||||
|
ln -sf Versions/Current/libfido2 "$FRAMEWORK_PATH/libfido2"
|
||||||
|
ln -sf Versions/Current/Resources "$FRAMEWORK_PATH/Resources"
|
||||||
|
|
||||||
|
echo "libfido2.framework structure fixed"
|
||||||
|
fi
|
||||||
|
|
@ -139,6 +139,7 @@
|
||||||
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 */; };
|
||||||
|
E8EEAD1D2E79174F00BE67E8 /* XcodesIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = E8EEAD1C2E79174F00BE67E8 /* XcodesIcon.icon */; };
|
||||||
E8F44A1E296B4CD7002D6592 /* Path in Frameworks */ = {isa = PBXBuildFile; productRef = E8F44A1D296B4CD7002D6592 /* Path */; };
|
E8F44A1E296B4CD7002D6592 /* Path in Frameworks */ = {isa = PBXBuildFile; productRef = E8F44A1D296B4CD7002D6592 /* Path */; };
|
||||||
E8FA00542B5B109800769CE0 /* com.xcodesorg.xcodesapp.Helper in Copy Helper */ = {isa = PBXBuildFile; fileRef = CA9FF8AE2595967A00E47BAF /* com.xcodesorg.xcodesapp.Helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
E8FA00542B5B109800769CE0 /* com.xcodesorg.xcodesapp.Helper in Copy Helper */ = {isa = PBXBuildFile; fileRef = CA9FF8AE2595967A00E47BAF /* com.xcodesorg.xcodesapp.Helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||||
E8FD5727291EE4AC001E004C /* AsyncNetworkService in Frameworks */ = {isa = PBXBuildFile; productRef = E8FD5726291EE4AC001E004C /* AsyncNetworkService */; };
|
E8FD5727291EE4AC001E004C /* AsyncNetworkService in Frameworks */ = {isa = PBXBuildFile; productRef = E8FD5726291EE4AC001E004C /* AsyncNetworkService */; };
|
||||||
|
|
@ -341,6 +342,7 @@
|
||||||
E8D655BF288DD04700A139C2 /* SelectedActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedActionType.swift; sourceTree = "<group>"; };
|
E8D655BF288DD04700A139C2 /* SelectedActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedActionType.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>"; };
|
||||||
|
E8EEAD1C2E79174F00BE67E8 /* XcodesIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = XcodesIcon.icon; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
|
@ -560,6 +562,7 @@
|
||||||
CABFAA1D2592F7F200380FEE /* Resources */ = {
|
CABFAA1D2592F7F200380FEE /* Resources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E8EEAD1C2E79174F00BE67E8 /* XcodesIcon.icon */,
|
||||||
CAA858DA25A3E11F00ACF8C0 /* aria2-release-1.35.0.tar.gz */,
|
CAA858DA25A3E11F00ACF8C0 /* aria2-release-1.35.0.tar.gz */,
|
||||||
CAA8588025A2B63A00ACF8C0 /* aria2c */,
|
CAA8588025A2B63A00ACF8C0 /* aria2c */,
|
||||||
CAA8588A25A2B69300ACF8C0 /* aria2c.LICENSE */,
|
CAA8588A25A2B69300ACF8C0 /* aria2c.LICENSE */,
|
||||||
|
|
@ -803,6 +806,7 @@
|
||||||
nl,
|
nl,
|
||||||
pl,
|
pl,
|
||||||
ar,
|
ar,
|
||||||
|
th,
|
||||||
);
|
);
|
||||||
mainGroup = CAD2E7952449574E00113D76;
|
mainGroup = CAD2E7952449574E00113D76;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
|
|
@ -837,6 +841,7 @@
|
||||||
files = (
|
files = (
|
||||||
CAD2E7A92449575000113D76 /* Preview Assets.xcassets in Resources */,
|
CAD2E7A92449575000113D76 /* Preview Assets.xcassets in Resources */,
|
||||||
9DD4FFCB2B13EC1800C974F1 /* Localizable.xcstrings in Resources */,
|
9DD4FFCB2B13EC1800C974F1 /* Localizable.xcstrings in Resources */,
|
||||||
|
E8EEAD1D2E79174F00BE67E8 /* XcodesIcon.icon in Resources */,
|
||||||
CA9FF83F2594FBC000E47BAF /* Licenses.rtf in Resources */,
|
CA9FF83F2594FBC000E47BAF /* Licenses.rtf 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 */,
|
||||||
|
|
@ -1092,13 +1097,14 @@
|
||||||
CA8FB636256E154800469DA5 /* Test */ = {
|
CA8FB636256E154800469DA5 /* Test */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = XcodesIcon;
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT = ZU6GR6B2FY;
|
CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT = ZU6GR6B2FY;
|
||||||
CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/XcodesTest.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/XcodesTest.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 32;
|
CURRENT_PROJECT_VERSION = 34;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
ENABLE_HARDENED_RUNTIME = NO;
|
ENABLE_HARDENED_RUNTIME = NO;
|
||||||
|
|
@ -1110,7 +1116,7 @@
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = 3.0.0;
|
MARKETING_VERSION = 3.0.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.xcodesorg.xcodesapp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.xcodesorg.xcodesapp;
|
||||||
PRODUCT_NAME = Xcodes;
|
PRODUCT_NAME = Xcodes;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|
@ -1344,13 +1350,14 @@
|
||||||
CAD2E7BD2449575100113D76 /* Debug */ = {
|
CAD2E7BD2449575100113D76 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = XcodesIcon;
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT = ZU6GR6B2FY;
|
CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT = ZU6GR6B2FY;
|
||||||
CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/Xcodes.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/Xcodes.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 32;
|
CURRENT_PROJECT_VERSION = 34;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = ZU6GR6B2FY;
|
DEVELOPMENT_TEAM = ZU6GR6B2FY;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
|
@ -1362,7 +1369,7 @@
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = 3.0.0;
|
MARKETING_VERSION = 3.0.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.xcodesorg.xcodesapp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.xcodesorg.xcodesapp;
|
||||||
PRODUCT_NAME = Xcodes;
|
PRODUCT_NAME = Xcodes;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|
@ -1372,13 +1379,14 @@
|
||||||
CAD2E7BE2449575100113D76 /* Release */ = {
|
CAD2E7BE2449575100113D76 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = XcodesIcon;
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT = ZU6GR6B2FY;
|
CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT = ZU6GR6B2FY;
|
||||||
CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/Xcodes.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Xcodes/Resources/Xcodes.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 32;
|
CURRENT_PROJECT_VERSION = 34;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = ZU6GR6B2FY;
|
DEVELOPMENT_TEAM = ZU6GR6B2FY;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
|
|
@ -1390,7 +1398,7 @@
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||||
MARKETING_VERSION = 3.0.0;
|
MARKETING_VERSION = 3.0.2;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.xcodesorg.xcodesapp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.xcodesorg.xcodesapp;
|
||||||
PRODUCT_NAME = Xcodes;
|
PRODUCT_NAME = Xcodes;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|
@ -1490,10 +1498,10 @@
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
33027E282CA8BB5800CB387C /* XCRemoteSwiftPackageReference "LibFido2Swift" */ = {
|
33027E282CA8BB5800CB387C /* XCRemoteSwiftPackageReference "LibFido2Swift" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/kinoroy/LibFido2Swift.git";
|
repositoryURL = "https://github.com/kinoroy/LibFido2Swift";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMinorVersion;
|
branch = main;
|
||||||
minimumVersion = 0.1.4;
|
kind = branch;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
CAA858CB25A3D8BC00ACF8C0 /* XCRemoteSwiftPackageReference "ErrorHandling" */ = {
|
CAA858CB25A3D8BC00ACF8C0 /* XCRemoteSwiftPackageReference "ErrorHandling" */ = {
|
||||||
|
|
|
||||||
|
|
@ -66,11 +66,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package": "LibFido2Swift",
|
"package": "LibFido2Swift",
|
||||||
"repositoryURL": "https://github.com/kinoroy/LibFido2Swift.git",
|
"repositoryURL": "https://github.com/kinoroy/LibFido2Swift",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": "main",
|
||||||
"revision": "94d496d6f850dcbb3e8c4a27cd7eeabfad9f14e3",
|
"revision": "b87a93300c5b35307c9f26ae490963196bd927f1",
|
||||||
"version": "0.1.4"
|
"version": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ extension AppState {
|
||||||
if selectedXcode.version > Version(major: 16, minor: 0, patch: 0) {
|
if selectedXcode.version > Version(major: 16, minor: 0, patch: 0) {
|
||||||
|
|
||||||
if runtime.architectures?.isAppleSilicon ?? false {
|
if runtime.architectures?.isAppleSilicon ?? false {
|
||||||
if selectedXcode.version > Version(major: 26, minor: 0, patch: 0) {
|
// Need Xcode 26 but with some RC/Beta's its simpler to just to greater > 25
|
||||||
|
if selectedXcode.version > Version(major: 25, minor: 0, patch: 0) {
|
||||||
downloadRuntimeViaXcodeBuild(runtime: runtime)
|
downloadRuntimeViaXcodeBuild(runtime: runtime)
|
||||||
} else {
|
} else {
|
||||||
// not supported
|
// not supported
|
||||||
|
|
|
||||||
|
|
@ -611,7 +611,11 @@ class AppState: ObservableObject {
|
||||||
self.installationPublishers[id] = nil
|
self.installationPublishers[id] = nil
|
||||||
if case let .failure(error) = completion {
|
if case let .failure(error) = completion {
|
||||||
// Prevent setting the app state error if it is an invalid session, we will present the sign in view instead
|
// Prevent setting the app state error if it is an invalid session, we will present the sign in view instead
|
||||||
if error as? AuthenticationError != .invalidSession {
|
if let error = error as? AuthenticationError, case .notAuthorized = error {
|
||||||
|
self.error = error
|
||||||
|
self.presentedAlert = .unauthenticated
|
||||||
|
|
||||||
|
} else if error as? AuthenticationError != .invalidSession {
|
||||||
self.error = error
|
self.error = error
|
||||||
self.presentedAlert = .generic(title: localizeString("Alert.Install.Error.Title"), message: error.legibleLocalizedDescription)
|
self.presentedAlert = .generic(title: localizeString("Alert.Install.Error.Title"), message: error.legibleLocalizedDescription)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ enum XcodesAlert: Identifiable {
|
||||||
case privilegedHelper
|
case privilegedHelper
|
||||||
case generic(title: String, message: String)
|
case generic(title: String, message: String)
|
||||||
case checkMinSupportedVersion(xcode: AvailableXcode, macOS: String)
|
case checkMinSupportedVersion(xcode: AvailableXcode, macOS: String)
|
||||||
|
case unauthenticated
|
||||||
|
|
||||||
var id: Int {
|
var id: Int {
|
||||||
switch self {
|
switch self {
|
||||||
|
|
@ -15,6 +16,7 @@ enum XcodesAlert: Identifiable {
|
||||||
case .generic: return 3
|
case .generic: return 3
|
||||||
case .checkMinSupportedVersion: return 4
|
case .checkMinSupportedVersion: return 4
|
||||||
case .cancelRuntimeInstall: return 5
|
case .cancelRuntimeInstall: return 5
|
||||||
|
case .unauthenticated: return 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import XcodesKit
|
||||||
|
|
||||||
struct PlatformsView: View {
|
struct PlatformsView: View {
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
@AppStorage("selectedRuntimeArchitecture") private var selectedRuntimeArchitecture: Architecture = .arm64
|
@AppStorage("selectedRuntimeArchitecture") private var selectedVariant: ArchitectureVariant = .universal
|
||||||
|
|
||||||
let xcode: Xcode
|
let xcode: Xcode
|
||||||
|
|
||||||
|
|
@ -22,7 +22,9 @@ struct PlatformsView: View {
|
||||||
appState.downloadableRuntimes.filter {
|
appState.downloadableRuntimes.filter {
|
||||||
$0.sdkBuildUpdate?.contains(sdkBuild) ?? false &&
|
$0.sdkBuildUpdate?.contains(sdkBuild) ?? false &&
|
||||||
($0.architectures?.isEmpty ?? true ||
|
($0.architectures?.isEmpty ?? true ||
|
||||||
$0.architectures?.contains(selectedRuntimeArchitecture) ?? false)
|
($0.architectures?.isUniversal ?? false && selectedVariant == .universal) ||
|
||||||
|
($0.architectures?.isAppleSilicon ?? false && selectedVariant == .appleSilicon)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,21 +37,18 @@ struct PlatformsView: View {
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
if !architectures.isEmpty {
|
if !architectures.isEmpty {
|
||||||
Spacer()
|
Spacer()
|
||||||
Button {
|
Picker("Architecture", selection: $selectedVariant) {
|
||||||
switch selectedRuntimeArchitecture {
|
ForEach(ArchitectureVariant.allCases, id: \.self) { arch in
|
||||||
case .arm64: selectedRuntimeArchitecture = .x86_64
|
Label(arch.displayString, systemImage: arch.iconName)
|
||||||
case .x86_64: selectedRuntimeArchitecture = .arm64
|
.tag(arch)
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
switch selectedRuntimeArchitecture {
|
|
||||||
case .arm64:
|
|
||||||
Label(selectedRuntimeArchitecture.displayString, systemImage: "m4.button.horizontal")
|
|
||||||
.labelStyle(.trailingIcon)
|
|
||||||
case .x86_64:
|
|
||||||
Label(selectedRuntimeArchitecture.displayString, systemImage: "cpu.fill")
|
|
||||||
.labelStyle(.trailingIcon)
|
|
||||||
}
|
}
|
||||||
|
.labelStyle(.trailingIcon)
|
||||||
}
|
}
|
||||||
|
.pickerStyle(.menu)
|
||||||
|
.menuStyle(.button)
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.fixedSize()
|
||||||
|
.labelsHidden()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +75,7 @@ struct PlatformsView: View {
|
||||||
ForEach(runtime.architectures ?? [], id: \.self) { architecture in
|
ForEach(runtime.architectures ?? [], id: \.self) { architecture in
|
||||||
TagView(text: architecture.displayString)
|
TagView(text: architecture.displayString)
|
||||||
}
|
}
|
||||||
|
|
||||||
pathIfAvailable(xcode: xcode, runtime: runtime)
|
pathIfAvailable(xcode: xcode, runtime: runtime)
|
||||||
|
|
||||||
if runtime.installState == .notInstalled {
|
if runtime.installState == .notInstalled {
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,20 @@ struct MainWindow: View {
|
||||||
action: { appState.presentedAlert = nil }
|
action: { appState.presentedAlert = nil }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
case .unauthenticated:
|
||||||
|
return Alert(
|
||||||
|
title: Text("Alert.Install.Error.Title"),
|
||||||
|
message: Text("Alert.Install.AuthError.Message"),
|
||||||
|
primaryButton: .default(
|
||||||
|
Text("OK"),
|
||||||
|
action: {
|
||||||
|
appState.presentedSheet = .signIn
|
||||||
|
}
|
||||||
|
),
|
||||||
|
secondaryButton: .cancel(
|
||||||
|
Text("Cancel")
|
||||||
|
)
|
||||||
|
)
|
||||||
case let .checkMinSupportedVersion(xcode, deviceVersion):
|
case let .checkMinSupportedVersion(xcode, deviceVersion):
|
||||||
return Alert(
|
return Alert(
|
||||||
title: Text("Alert.MinSupported.Title"),
|
title: Text("Alert.MinSupported.Title"),
|
||||||
|
|
|
||||||
|
|
@ -22,60 +22,44 @@ struct MainToolbarModifier: ViewModifier {
|
||||||
}
|
}
|
||||||
.keyboardShortcut(KeyEquivalent("r"))
|
.keyboardShortcut(KeyEquivalent("r"))
|
||||||
.help("RefreshDescription")
|
.help("RefreshDescription")
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Button(action: {
|
|
||||||
switch architectures {
|
|
||||||
case .universal: architectures = .appleSilicon
|
|
||||||
case .appleSilicon: architectures = .universal
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
switch architectures {
|
|
||||||
case .universal:
|
|
||||||
Label("Universal", systemImage: "cpu.fill")
|
|
||||||
case .appleSilicon:
|
|
||||||
Label("Apple Silicon", systemImage: "m4.button.horizontal")
|
|
||||||
.labelStyle(.trailingIcon)
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.help("FilterAvailableDescription")
|
|
||||||
.disabled(architectures.isManaged)
|
|
||||||
|
|
||||||
Button(action: {
|
Spacer()
|
||||||
switch category {
|
|
||||||
case .all: category = .release
|
let isFiltering = isInstalledOnly || category != .all || architectures != .universal
|
||||||
case .release: category = .beta
|
Menu("Filter", systemImage: "line.horizontal.3.decrease.circle") {
|
||||||
case .beta: category = .all
|
Section {
|
||||||
|
Toggle("Installed Only", systemImage: "arrow.down.app", isOn: $isInstalledOnly) .labelStyle(.titleAndIcon)
|
||||||
}
|
}
|
||||||
}) {
|
.help("FilterInstalledDescription")
|
||||||
switch category {
|
|
||||||
case .all:
|
Section {
|
||||||
Label("All", systemImage: "line.horizontal.3.decrease.circle")
|
Picker("Category", selection: $category) {
|
||||||
case .release:
|
Label("All", systemImage: "line.horizontal.3.decrease.circle")
|
||||||
|
.tag(XcodeListCategory.all)
|
||||||
Label("ReleaseOnly", systemImage: "line.horizontal.3.decrease.circle.fill")
|
Label("ReleaseOnly", systemImage: "line.horizontal.3.decrease.circle.fill")
|
||||||
.labelStyle(.trailingIcon)
|
.tag(XcodeListCategory.release)
|
||||||
|
Label("BetaOnly", systemImage: "line.horizontal.3.decrease.circle.fill")
|
||||||
|
.tag(XcodeListCategory.beta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.help("FilterAvailableDescription")
|
||||||
|
.disabled(category.isManaged)
|
||||||
|
|
||||||
|
Section {
|
||||||
|
Picker("Architecture", selection: $architectures) {
|
||||||
|
Label("Universal", systemImage: "cpu.fill")
|
||||||
|
.tag(XcodeListArchitecture.universal)
|
||||||
|
Label("Apple Silicon", systemImage: "m4.button.horizontal")
|
||||||
.foregroundColor(.accentColor)
|
.foregroundColor(.accentColor)
|
||||||
case .beta:
|
.tag(XcodeListArchitecture.appleSilicon)
|
||||||
Label("BetaOnly", systemImage: "line.horizontal.3.decrease.circle.fill")
|
}
|
||||||
.labelStyle(.trailingIcon)
|
.help("FilterArchitecturesDescription")
|
||||||
.foregroundColor(.accentColor)
|
.disabled(architectures.isManaged)
|
||||||
}
|
}
|
||||||
|
.labelStyle(.titleAndIcon)
|
||||||
}
|
}
|
||||||
.help("FilterAvailableDescription")
|
.pickerStyle(.inline)
|
||||||
.disabled(category.isManaged)
|
.symbolVariant(isFiltering ? .fill : .none)
|
||||||
|
|
||||||
Button(action: {
|
|
||||||
isInstalledOnly.toggle()
|
|
||||||
}) {
|
|
||||||
if isInstalledOnly {
|
|
||||||
Label("Filter", systemImage: "arrow.down.app.fill")
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
} else {
|
|
||||||
Label("Filter", systemImage: "arrow.down.app")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.help("FilterInstalledDescription")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ struct XcodeListView: View {
|
||||||
PlatformsPocket()
|
PlatformsPocket()
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,20 +84,30 @@ struct PlatformsPocket: View {
|
||||||
openWindow(id: "platforms")
|
openWindow(id: "platforms")
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
HStack(spacing: 5) {
|
if #available(macOS 26.0, *) {
|
||||||
Image(systemName: "square.3.layers.3d")
|
platformsLabel
|
||||||
.font(.title3.weight(.medium))
|
.glassEffect(in: .rect(cornerRadius: 8, style: .continuous))
|
||||||
Text("PlatformsDescription")
|
} else {
|
||||||
Spacer()
|
platformsLabel
|
||||||
|
.background(.quaternary.opacity(0.75))
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
|
||||||
}
|
}
|
||||||
.font(.body.weight(.medium))
|
|
||||||
.padding(.horizontal)
|
|
||||||
.padding(.vertical, 12)
|
|
||||||
.background(.quaternary.opacity(0.75))
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var platformsLabel: some View {
|
||||||
|
HStack(spacing: 5) {
|
||||||
|
Image(systemName: "square.3.layers.3d")
|
||||||
|
.font(.title3.weight(.medium))
|
||||||
|
Text("PlatformsDescription")
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.font(.body.weight(.medium))
|
||||||
|
.padding(.horizontal)
|
||||||
|
.padding(.vertical, 12)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XcodeListView_Previews: PreviewProvider {
|
struct XcodeListView_Previews: PreviewProvider {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{\rtf1\ansi\ansicpg1252\cocoartf2822
|
{\rtf1\ansi\ansicpg1252\cocoartf2865
|
||||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 .SFNS-Regular;}
|
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 .SFNS-Regular;}
|
||||||
{\colortbl;\red255\green255\blue255;}
|
{\colortbl;\red255\green255\blue255;}
|
||||||
{\*\expandedcolortbl;;}
|
{\*\expandedcolortbl;;}
|
||||||
|
|
|
||||||
BIN
Xcodes/Resources/XcodesIcon.icon/Assets/Dark.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Xcodes/Resources/XcodesIcon.icon/Assets/Light.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
Xcodes/Resources/XcodesIcon.icon/Assets/Mono.png
Normal file
|
After Width: | Height: | Size: 716 KiB |
50
Xcodes/Resources/XcodesIcon.icon/icon.json
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"fill" : {
|
||||||
|
"automatic-gradient" : "extended-srgb:0.00000,0.47843,1.00000,1.00000"
|
||||||
|
},
|
||||||
|
"groups" : [
|
||||||
|
{
|
||||||
|
"layers" : [
|
||||||
|
{
|
||||||
|
"glass" : false,
|
||||||
|
"hidden" : false,
|
||||||
|
"image-name-specializations" : [
|
||||||
|
{
|
||||||
|
"value" : "Light.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearance" : "dark",
|
||||||
|
"value" : "Dark.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearance" : "tinted",
|
||||||
|
"value" : "Mono.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name" : "Dark",
|
||||||
|
"position" : {
|
||||||
|
"scale" : 1,
|
||||||
|
"translation-in-points" : [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"shadow" : {
|
||||||
|
"kind" : "neutral",
|
||||||
|
"opacity" : 0.5
|
||||||
|
},
|
||||||
|
"specular" : false,
|
||||||
|
"translucency" : {
|
||||||
|
"enabled" : false,
|
||||||
|
"value" : 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"supported-platforms" : {
|
||||||
|
"squares" : [
|
||||||
|
"macOS"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "XcodesKit",
|
name: "XcodesKit",
|
||||||
platforms: [.macOS(.v11)],
|
platforms: [.macOS(.v13)],
|
||||||
products: [
|
products: [
|
||||||
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||||
.library(
|
.library(
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// The name of an Architecture.
|
/// The name of an Architecture.
|
||||||
public enum Architecture: String, Codable, Equatable, Hashable, Identifiable {
|
public enum Architecture: String, Codable, Equatable, Hashable, Identifiable, CaseIterable {
|
||||||
public var id: Self { self }
|
public var id: Self { self }
|
||||||
|
|
||||||
/// The Arm64 architecture (Apple Silicon)
|
/// The Arm64 architecture (Apple Silicon)
|
||||||
|
|
@ -24,10 +24,48 @@ public enum Architecture: String, Codable, Equatable, Hashable, Identifiable {
|
||||||
return "Intel"
|
return "Intel"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var iconName: String {
|
||||||
|
switch self {
|
||||||
|
case .arm64:
|
||||||
|
return "m4.button.horizontal"
|
||||||
|
case .x86_64:
|
||||||
|
return "cpu.fill"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ArchitectureVariant: String, Codable, Equatable, Hashable, Identifiable, CaseIterable {
|
||||||
|
public var id: Self { self }
|
||||||
|
|
||||||
|
case universal
|
||||||
|
case appleSilicon
|
||||||
|
|
||||||
|
public var displayString: String {
|
||||||
|
switch self {
|
||||||
|
case .appleSilicon:
|
||||||
|
return "Apple Silicon"
|
||||||
|
case .universal:
|
||||||
|
return "Universal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var iconName: String {
|
||||||
|
switch self {
|
||||||
|
case .appleSilicon:
|
||||||
|
return "m4.button.horizontal"
|
||||||
|
case .universal:
|
||||||
|
return "cpu.fill"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Array where Element == Architecture {
|
extension Array where Element == Architecture {
|
||||||
public var isAppleSilicon: Bool {
|
public var isAppleSilicon: Bool {
|
||||||
self == [.arm64]
|
self == [.arm64]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var isUniversal: Bool {
|
||||||
|
self.contains([.arm64, .x86_64])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
icon.png
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 22 KiB |