From 192a1c6371858949c368a44b108240deb9708fef Mon Sep 17 00:00:00 2001 From: Brandon Evans Date: Sun, 27 Dec 2020 23:25:26 -0700 Subject: [PATCH 1/3] Move all toolbar items to status position, use filter button instead of picker --- Xcodes/Frontend/XcodeList/XcodeListView.swift | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Xcodes/Frontend/XcodeList/XcodeListView.swift b/Xcodes/Frontend/XcodeList/XcodeListView.swift index d10eb8a..04a6eb4 100644 --- a/Xcodes/Frontend/XcodeList/XcodeListView.swift +++ b/Xcodes/Frontend/XcodeList/XcodeListView.swift @@ -81,7 +81,7 @@ struct XcodeListView: View { } } .toolbar { - ToolbarItemGroup(placement: .primaryAction) { + ToolbarItemGroup(placement: .status) { Button(action: appState.update) { Label("Refresh", systemImage: "arrow.clockwise") } @@ -93,16 +93,22 @@ struct XcodeListView: View { .scaleEffect(0.5, anchor: .center) .isHidden(!appState.isUpdating) ) - } - ToolbarItem(placement: .principal) { - Picker("", selection: $category) { - ForEach(Category.allCases, id: \.self) { - Text($0.description).tag($0) + + Button(action: { + switch category { + case .all: category = .installed + case .installed: category = .all + } + }) { + switch category { + case .all: + Label("Filter", systemImage: "line.horizontal.3.decrease.circle") + case .installed: + Label("Filter", systemImage: "line.horizontal.3.decrease.circle.fill") + .foregroundColor(.accentColor) } } - .pickerStyle(SegmentedPickerStyle()) - } - ToolbarItem { + TextField("Search...", text: $searchText) .textFieldStyle(RoundedBorderTextFieldStyle()) .frame(width: 200) From 4cb60e29297c922a8b88798fcfccd3826efab022 Mon Sep 17 00:00:00 2001 From: Brandon Evans Date: Sun, 27 Dec 2020 23:42:07 -0700 Subject: [PATCH 2/3] Extract MainToolbar --- Xcodes.xcodeproj/project.pbxproj | 6 +- Xcodes/Frontend/XcodeList/MainToolbar.swift | 56 +++++++++++++++++++ Xcodes/Frontend/XcodeList/XcodeListView.swift | 35 +----------- 3 files changed, 62 insertions(+), 35 deletions(-) create mode 100644 Xcodes/Frontend/XcodeList/MainToolbar.swift diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index 787db19..5852ae2 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -71,6 +71,7 @@ CAD2E7B82449575100113D76 /* XcodesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD2E7B72449575100113D76 /* XcodesTests.swift */; }; CAFBDB912598FE80003DCC5A /* SelectedXcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDB902598FE80003DCC5A /* SelectedXcode.swift */; }; CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDB942598FE96003DCC5A /* FocusedValues.swift */; }; + CAFBDC4E2599B33D003DCC5A /* MainToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDC4D2599B33D003DCC5A /* MainToolbar.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -189,6 +190,7 @@ CAFBDB902598FE80003DCC5A /* SelectedXcode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedXcode.swift; sourceTree = ""; }; CAFBDB942598FE96003DCC5A /* FocusedValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusedValues.swift; sourceTree = ""; }; CAFBDBA525990C76003DCC5A /* SimpleXPCApp.LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = SimpleXPCApp.LICENSE; sourceTree = ""; }; + CAFBDC4D2599B33D003DCC5A /* MainToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainToolbar.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -292,9 +294,10 @@ CABFAA142592F73000380FEE /* XcodeList */ = { isa = PBXGroup; children = ( - CAD2E7A32449574E00113D76 /* XcodeListView.swift */, CA39711824495F0E00AFFB77 /* AppStoreButtonStyle.swift */, + CAFBDC4D2599B33D003DCC5A /* MainToolbar.swift */, CA44901E2463AD34003D8213 /* Tag.swift */, + CAD2E7A32449574E00113D76 /* XcodeListView.swift */, ); path = XcodeList; sourceTree = ""; @@ -599,6 +602,7 @@ files = ( CA9FF8CF25959A9700E47BAF /* HelperXPCShared.swift in Sources */, CA735109257BF96D00EA9CF8 /* AttributedText.swift in Sources */, + CAFBDC4E2599B33D003DCC5A /* MainToolbar.swift in Sources */, CA11E7BA2598476C00D2EE1C /* XcodeCommands.swift in Sources */, CABFAA492593162500380FEE /* Bundle+InfoPlistValues.swift in Sources */, CA9FF8662595130600E47BAF /* View+IsHidden.swift in Sources */, diff --git a/Xcodes/Frontend/XcodeList/MainToolbar.swift b/Xcodes/Frontend/XcodeList/MainToolbar.swift new file mode 100644 index 0000000..3ea81d6 --- /dev/null +++ b/Xcodes/Frontend/XcodeList/MainToolbar.swift @@ -0,0 +1,56 @@ +import SwiftUI + +struct MainToolbarModifier: ViewModifier { + @EnvironmentObject var appState: AppState + @Binding var category: XcodeListView.Category + @Binding var searchText: String + + func body(content: Content) -> some View { + content + .toolbar { toolbar } + } + + private var toolbar: some ToolbarContent { + ToolbarItemGroup(placement: .status) { + Button(action: appState.update) { + Label("Refresh", systemImage: "arrow.clockwise") + } + .keyboardShortcut(KeyEquivalent("r")) + .disabled(appState.isUpdating) + .isHidden(appState.isUpdating) + .overlay( + ProgressView() + .scaleEffect(0.5, anchor: .center) + .isHidden(!appState.isUpdating) + ) + + Button(action: { + switch category { + case .all: category = .installed + case .installed: category = .all + } + }) { + switch category { + case .all: + Label("Filter", systemImage: "line.horizontal.3.decrease.circle") + case .installed: + Label("Filter", systemImage: "line.horizontal.3.decrease.circle.fill") + .foregroundColor(.accentColor) + } + } + + TextField("Search...", text: $searchText) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .frame(width: 200) + } + } +} + +extension View { + func mainToolbar( + category: Binding, + searchText: Binding + ) -> some View { + self.modifier(MainToolbarModifier(category: category, searchText: searchText)) + } +} diff --git a/Xcodes/Frontend/XcodeList/XcodeListView.swift b/Xcodes/Frontend/XcodeList/XcodeListView.swift index 04a6eb4..d58b9fb 100644 --- a/Xcodes/Frontend/XcodeList/XcodeListView.swift +++ b/Xcodes/Frontend/XcodeList/XcodeListView.swift @@ -80,40 +80,7 @@ struct XcodeListView: View { } } } - .toolbar { - ToolbarItemGroup(placement: .status) { - Button(action: appState.update) { - Label("Refresh", systemImage: "arrow.clockwise") - } - .keyboardShortcut(KeyEquivalent("r")) - .disabled(appState.isUpdating) - .isHidden(appState.isUpdating) - .overlay( - ProgressView() - .scaleEffect(0.5, anchor: .center) - .isHidden(!appState.isUpdating) - ) - - Button(action: { - switch category { - case .all: category = .installed - case .installed: category = .all - } - }) { - switch category { - case .all: - Label("Filter", systemImage: "line.horizontal.3.decrease.circle") - case .installed: - Label("Filter", systemImage: "line.horizontal.3.decrease.circle.fill") - .foregroundColor(.accentColor) - } - } - - TextField("Search...", text: $searchText) - .textFieldStyle(RoundedBorderTextFieldStyle()) - .frame(width: 200) - } - } + .mainToolbar(category: $category, searchText: $searchText) .navigationSubtitle(subtitleText) .frame(minWidth: 200, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity) .alert(item: $appState.error) { error in From 09653b7357e3bc14782fc33e38b3a54cef06b23c Mon Sep 17 00:00:00 2001 From: Brandon Evans Date: Mon, 28 Dec 2020 11:57:45 -0700 Subject: [PATCH 3/3] Use ProgressButton in MainToolbar Made a small change to how ProgressButton is constructed to prevent its frame changing when isInProgress changes. --- Xcodes/Frontend/Common/ProgressButton.swift | 18 +++++++++++------- Xcodes/Frontend/XcodeList/MainToolbar.swift | 12 ++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Xcodes/Frontend/Common/ProgressButton.swift b/Xcodes/Frontend/Common/ProgressButton.swift index 2b6668d..34b6f6e 100644 --- a/Xcodes/Frontend/Common/ProgressButton.swift +++ b/Xcodes/Frontend/Common/ProgressButton.swift @@ -21,13 +21,17 @@ struct ProgressButton: View { var body: some View { Button(action: action) { - if isInProgress { - ProgressView() - .progressViewStyle(CircularProgressViewStyle()) - .scaleEffect(x: 0.5, y: 0.5, anchor: .center) - } else { - label() - } + // This might look like a strange way to switch between the label and the progress view. + // Doing it this way, so that the label is hidden but still has the same frame and is in the view hierarchy + // makes sure that the button's frame doesn't change when isInProgress changes. + label() + .isHidden(isInProgress) + .overlay( + ProgressView() + .progressViewStyle(CircularProgressViewStyle()) + .scaleEffect(x: 0.5, y: 0.5, anchor: .center) + .isHidden(!isInProgress) + ) } .disabled(isInProgress) } diff --git a/Xcodes/Frontend/XcodeList/MainToolbar.swift b/Xcodes/Frontend/XcodeList/MainToolbar.swift index 3ea81d6..1c60822 100644 --- a/Xcodes/Frontend/XcodeList/MainToolbar.swift +++ b/Xcodes/Frontend/XcodeList/MainToolbar.swift @@ -12,17 +12,13 @@ struct MainToolbarModifier: ViewModifier { private var toolbar: some ToolbarContent { ToolbarItemGroup(placement: .status) { - Button(action: appState.update) { + ProgressButton( + isInProgress: appState.isUpdating, + action: appState.update + ) { Label("Refresh", systemImage: "arrow.clockwise") } .keyboardShortcut(KeyEquivalent("r")) - .disabled(appState.isUpdating) - .isHidden(appState.isUpdating) - .overlay( - ProgressView() - .scaleEffect(0.5, anchor: .center) - .isHidden(!appState.isUpdating) - ) Button(action: { switch category {