Compare commits

...

26 commits

Author SHA1 Message Date
Matt Kiazyk
1a0d3353b9 update readme with v3 changes 2025-09-19 23:53:54 -05:00
Matt Kiazyk
da8d22c6d3 bad package.resolved 2025-09-19 19:56:41 -05:00
Matt Kiazyk
4f9b7f8f6a remove old libfido2swift fix 2025-09-19 19:31:16 -05:00
Matt Kiazyk
f34e291433 3.0.2 2025-09-19 19:20:34 -05:00
Matt Kiazyk
789eedcdb7 add some glass effect... why not? 2025-09-19 19:19:58 -05:00
Matt Kiazyk
f9262d9a05 fix for codesign issues with libfido2swift 2025-09-19 19:19:48 -05:00
Matt Kiazyk
4776af75ee 3.0.1 2025-09-17 23:01:03 -05:00
Matt Kiazyk
cab5533b49
Merge pull request #756 from neetrath/main
Add Thai translations
2025-09-17 22:55:26 -05:00
Matt Kiazyk
fc50db1cee fix how platforms are architecture filtered 2025-09-17 22:37:19 -05:00
Ruttanachai Auitragool
576585b7de feat: Add Thai translations 2025-09-16 23:22:44 +07:00
Matt Kiazyk
6cf9647840
Merge pull request #755 from XcodesOrg/newIcon
New Icon - who dis?
2025-09-16 10:43:43 -05:00
Matt Kiazyk
90dccd8180 new fancy app icon! 2025-09-15 23:08:51 -05:00
Matt Kiazyk
372d5b1f4e
Merge pull request #753 from XcodesOrg/matt/FixXcoded26Check
fix: xcode 26 check for Apple Silicon installs
2025-09-15 22:59:56 -05:00
Matt Kiazyk
4063796833
Merge pull request #727 from megabitsenmzq/main
Update zh_Hans translations.
2025-09-15 22:42:13 -05:00
Matt Kiazyk
be2eea0532
Merge pull request #746 from LiYanan2004/filter-ux
Improve filtering UI/UX on Xcode List
2025-09-15 22:41:32 -05:00
Matt Kiazyk
a6dec75603 fix libfido2 errors on Xcode26 thanks @anciltech 2025-09-15 22:34:19 -05:00
Matt Kiazyk
9527fb2961 fix: xcode 26 check for Apple Silicon installs 2025-09-15 22:08:49 -05:00
Matt Kiazyk
084bd8f4a1
Merge pull request #744 from leschlogl/feature/portuguese-translations
Fixes Brazilian Portuguese translations
2025-09-15 22:06:46 -05:00
Lucas Eduardo Schlögl
f93da1c502 small translation improvements 2025-09-10 14:43:20 +02:00
LiYanan2004
79ef494504 Add icon for "Installed Only" filter 2025-09-02 22:22:55 +08:00
LiYanan2004
cdf3675a5e Improve filtering UI 2025-09-02 14:40:35 +08:00
Jinyu Meng
5974a85800 Update zh_Hans translations.
# Conflicts:
#	Xcodes/Resources/Localizable.xcstrings
2025-08-29 11:45:06 +09:00
Matt Kiazyk
4ccb6e7f06
Merge pull request #741 from r1b2ns/feat/redirect-new-user-to-login
feat: improve user experience with a redirect window to sign-in
2025-08-27 08:37:19 -05:00
Rubens
22e4991f9a
chore: add new localized string in all languages 2025-08-27 10:32:20 -03:00
Lucas Eduardo Schlögl
059c51b5dd Fixes Brazilian Portuguese translations 2025-08-27 13:30:47 +02:00
Rubens
bbec397613
feat: add button to redirect user when this try to install a xcode version without signed 2025-08-20 08:38:16 -03:00
22 changed files with 1569 additions and 130 deletions

BIN
IconDark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
IconMono.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -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.

View 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

View file

@ -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" */ = {

View file

@ -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
} }
}, },
{ {

View file

@ -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

View file

@ -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)
} }

View file

@ -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
} }
} }
} }

View file

@ -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 {

View file

@ -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"),

View file

@ -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")
} }
} }
} }

View file

@ -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 {

View file

@ -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;;}

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 KiB

View 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"
]
}
}

View file

@ -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(

View file

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 22 KiB