diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index 4064e96..e634c89 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -848,10 +848,12 @@ /* Begin PBXShellScriptBuildPhase section */ 05EACA532E76D21100CF1F9D /* Fix libfido2 structure */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; name = "Fix libfido2 structure"; shellPath = /bin/sh; shellScript = ( - "/Users/genesis/Coding/XCode/OpenSourceContributions/XcodesApp/Scripts/fix_libfido2_framework.sh", + "./Scripts/fix_libfido2_framework.sh", + "", "", ); }; @@ -874,6 +876,8 @@ "", "", "", + "", + "", ); }; /* End PBXShellScriptBuildPhase section */ @@ -1060,6 +1064,7 @@ COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; @@ -1102,7 +1107,7 @@ CURRENT_PROJECT_VERSION = 33; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_HARDENED_RUNTIME = NO; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Xcodes/Resources/Info.plist; @@ -1152,7 +1157,7 @@ CODE_SIGN_STYLE = Automatic; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = 9NP473RSFG; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = "$(SRCROOT)/$(TARGET_NAME)/Info.plist"; MARKETING_VERSION = 2.0.0; @@ -1179,7 +1184,7 @@ CODE_SIGN_STYLE = Manual; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_HARDENED_RUNTIME = NO; INFOPLIST_FILE = "$(SRCROOT)/$(TARGET_NAME)/Info.plist"; MARKETING_VERSION = 2.0.0; @@ -1207,7 +1212,7 @@ CODE_SIGN_STYLE = Automatic; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = 9NP473RSFG; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = "$(SRCROOT)/$(TARGET_NAME)/Info.plist"; MARKETING_VERSION = 2.0.0; @@ -1264,6 +1269,7 @@ COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; @@ -1333,6 +1339,7 @@ COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; @@ -1368,7 +1375,7 @@ CURRENT_PROJECT_VERSION = 33; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\""; - DEVELOPMENT_TEAM = 9NP473RSFG; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Xcodes/Resources/Info.plist; @@ -1397,7 +1404,7 @@ CURRENT_PROJECT_VERSION = 33; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\""; - DEVELOPMENT_TEAM = 9NP473RSFG; + DEVELOPMENT_TEAM = ZU6GR6B2FY; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = Xcodes/Resources/Info.plist; diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index 1f6419d..1b80390 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -139,6 +139,12 @@ class AppState: ObservableObject { } } + @Published var collapsableListEnabled = true { + didSet { + Current.defaults.set(collapsableListEnabled, forKey: "collapsableListEnabled") + } + } + // MARK: - Runtimes @Published var downloadableRuntimes: [DownloadableRuntime] = [] @@ -209,6 +215,7 @@ class AppState: ObservableObject { installPath = Current.defaults.string(forKey: "installPath") ?? Path.defaultInstallDirectory.string showOpenInRosettaOption = Current.defaults.bool(forKey: "showOpenInRosettaOption") ?? false terminateAfterLastWindowClosed = Current.defaults.bool(forKey: "terminateAfterLastWindowClosed") ?? false + collapsableListEnabled = Current.defaults.bool(forKey: "collapsibleListEnabled") ?? true } // MARK: Timer diff --git a/Xcodes/Frontend/Preferences/GeneralPreferencePane.swift b/Xcodes/Frontend/Preferences/GeneralPreferencePane.swift index b15f5c6..de4f3b8 100644 --- a/Xcodes/Frontend/Preferences/GeneralPreferencePane.swift +++ b/Xcodes/Frontend/Preferences/GeneralPreferencePane.swift @@ -24,6 +24,7 @@ struct GeneralPreferencePane: View { GroupBox(label: Text("Misc")) { Toggle("TerminateAfterLastWindowClosed", isOn: $appState.terminateAfterLastWindowClosed) + Toggle("EnableCollapsibleList", isOn: $appState.collapsableListEnabled) } .groupBoxStyle(PreferencesGroupBoxStyle()) } diff --git a/Xcodes/Frontend/XcodeList/XcodeListView.swift b/Xcodes/Frontend/XcodeList/XcodeListView.swift index 3704f38..2eb6406 100644 --- a/Xcodes/Frontend/XcodeList/XcodeListView.swift +++ b/Xcodes/Frontend/XcodeList/XcodeListView.swift @@ -70,53 +70,16 @@ struct XcodeListView: View { var body: some View { List(selection: $selectedXcodeID) { - ForEach(majorVersionGroups) { majorVersionGroup in - let isMajorExpanded = expandedMajorVersions.contains(majorVersionGroup.majorVersion) - - XcodeMajorVersionRow( - majorVersionGroup: majorVersionGroup, - isExpanded: isMajorExpanded, - onToggleExpanded: { - if isMajorExpanded { - expandedMajorVersions.remove(majorVersionGroup.majorVersion) - // Collapse all minor versions when major version is collapsed - for minorGroup in majorVersionGroup.minorVersionGroups { - expandedMinorVersions.remove(minorGroup.id) - } - } else { - expandedMajorVersions.insert(majorVersionGroup.majorVersion) - } - }, + if appState.collapsableListEnabled { + CollapsableListView( + visibleXcodes: visibleXcodes, + selectedXcodeID: $selectedXcodeID, appState: appState ) - .tag(majorVersionGroup.selectedVersion?.id) - - if isMajorExpanded { - ForEach(majorVersionGroup.minorVersionGroups) { minorVersionGroup in - let isMinorExpanded = expandedMinorVersions.contains(minorVersionGroup.id) - - XcodeMinorVersionRow( - minorVersionGroup: minorVersionGroup, - isExpanded: isMinorExpanded, - onToggleExpanded: { - if isMinorExpanded { - expandedMinorVersions.remove(minorVersionGroup.id) - } else { - expandedMinorVersions.insert(minorVersionGroup.id) - } - }, - appState: appState - ) - .tag(minorVersionGroup.selectedVersion?.id) - - if isMinorExpanded { - ForEach(minorVersionGroup.versions) { xcode in - XcodeListViewRow(xcode: xcode, selected: selectedXcodeID == xcode.id, appState: appState) - .padding(.leading, 40) - .tag(xcode.id) - } - } - } + } else { + ForEach(visibleXcodes) { xcode in + XcodeListViewRow(xcode: xcode, selected: selectedXcodeID == xcode.id, appState: appState) + .tag(xcode.id) } } } @@ -129,6 +92,72 @@ struct XcodeListView: View { } } +struct CollapsableListView: View { + let visibleXcodes: [Xcode] + @Binding var selectedXcodeID: Xcode.ID? + let appState: AppState + + @State private var expandedMajorVersions = Set() + @State private var expandedMinorVersions = Set() + + var majorVersionGroups: [XcodeMajorVersionGroup] { + visibleXcodes.groupedByMajorVersion() + } + + var body: some View { + ForEach(majorVersionGroups) { majorVersionGroup in + let isMajorExpanded = expandedMajorVersions.contains(majorVersionGroup.majorVersion) + + XcodeMajorVersionRow( + majorVersionGroup: majorVersionGroup, + isExpanded: isMajorExpanded, + onToggleExpanded: { + if isMajorExpanded { + expandedMajorVersions.remove(majorVersionGroup.majorVersion) + // Collapse all minor versions when major version is collapsed + for minorGroup in majorVersionGroup.minorVersionGroups { + expandedMinorVersions.remove(minorGroup.id) + } + } else { + expandedMajorVersions.insert(majorVersionGroup.majorVersion) + } + }, + appState: appState + ) + .tag(majorVersionGroup.selectedVersion?.id) + + if isMajorExpanded { + ForEach(majorVersionGroup.minorVersionGroups) { minorVersionGroup in + let isMinorExpanded = expandedMinorVersions.contains(minorVersionGroup.id) + + XcodeMinorVersionRow( + minorVersionGroup: minorVersionGroup, + isExpanded: isMinorExpanded, + onToggleExpanded: { + if isMinorExpanded { + expandedMinorVersions.remove(minorVersionGroup.id) + } else { + expandedMinorVersions.insert(minorVersionGroup.id) + } + }, + appState: appState + ) + .tag(minorVersionGroup.selectedVersion?.id) + + if isMinorExpanded { + ForEach(minorVersionGroup.versions) { xcode in + XcodeListViewRow(xcode: xcode, selected: selectedXcodeID == xcode.id, appState: appState) + .padding(.leading, 40) + .tag(xcode.id) + } + } + } + } + } + } +} + + struct PlatformsPocket: View { @SwiftUI.Environment(\.openWindow) private var openWindow @@ -175,3 +204,4 @@ struct XcodeListView_Previews: PreviewProvider { .previewLayout(.sizeThatFits) } } + diff --git a/Xcodes/Frontend/XcodeList/XcodeMajorVersionRow.swift b/Xcodes/Frontend/XcodeList/XcodeMajorVersionRow.swift index 8eadb37..6008417 100644 --- a/Xcodes/Frontend/XcodeList/XcodeMajorVersionRow.swift +++ b/Xcodes/Frontend/XcodeList/XcodeMajorVersionRow.swift @@ -19,11 +19,11 @@ struct XcodeMajorVersionRow: View { majorVersionIcon VStack(alignment: .leading, spacing: 2) { - Text("Xcode \(majorVersionGroup.displayName)") + Text(String(format: localizeString("Xcode %@"), majorVersionGroup.displayName)) .font(.body.weight(.medium)) if let latestRelease = majorVersionGroup.latestRelease { - Text("Latest: \(latestRelease.description)") + Text(String(format: localizeString("Latest: %@"), latestRelease.description)) .font(.caption) .foregroundColor(.secondary) } diff --git a/Xcodes/Frontend/XcodeList/XcodeMinorVersionRow.swift b/Xcodes/Frontend/XcodeList/XcodeMinorVersionRow.swift index be8a2b3..c75ca21 100644 --- a/Xcodes/Frontend/XcodeList/XcodeMinorVersionRow.swift +++ b/Xcodes/Frontend/XcodeList/XcodeMinorVersionRow.swift @@ -19,11 +19,11 @@ struct XcodeMinorVersionRow: View { minorVersionIcon VStack(alignment: .leading, spacing: 2) { - Text("Xcode \(minorVersionGroup.displayName)") + Text(String(format: localizeString("Xcode %@"), minorVersionGroup.displayName)) .font(.callout.weight(.medium)) if let latestRelease = minorVersionGroup.latestRelease { - Text("Latest: \(latestRelease.description)") + Text(String(format: localizeString("Latest: %@"), latestRelease.description)) .font(.caption2) .foregroundColor(.secondary) } @@ -137,4 +137,4 @@ struct XcodeMinorVersionRow_Previews: PreviewProvider { ) .previewLayout(.sizeThatFits) } -} \ No newline at end of file +} diff --git a/Xcodes/Resources/Localizable.xcstrings b/Xcodes/Resources/Localizable.xcstrings index df80e79..772f874 100644 --- a/Xcodes/Resources/Localizable.xcstrings +++ b/Xcodes/Resources/Localizable.xcstrings @@ -8380,6 +8380,24 @@ } } }, + "EnableCollapsibleList" : { + "comment" : "A toggle that enables or disables the collapsible list feature.", + "isCommentAutoGenerated" : true, + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Haupt- und Unterversionen in der Listenansicht zusammenklappen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Collapse Major and Minor Versions in the list view" + } + } + } + }, "EnableNotifications" : { "localizations" : { "ar" : {