From 27fb9fc5bda50c8508d183d02d4e84148008bd4a Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Wed, 14 Aug 2024 15:22:42 +0200 Subject: [PATCH 1/9] feat(themes) add fuzzy search to filter and sort themes in settings --- CodeEdit.xcodeproj/project.pbxproj | 36 ++++++++------ .../Models/Theme+FuzzySearchable.swift | 14 ++++++ .../ThemeSettings/ThemeSettingsView.swift | 49 +++++++++++++------ 3 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/Models/Theme+FuzzySearchable.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index da9542be7..044580fed 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -339,6 +339,7 @@ 61A3E3E72C33383100076BD3 /* EnvironmentVariableListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A3E3E62C33383100076BD3 /* EnvironmentVariableListItem.swift */; }; 61A53A7E2B4449870093BF8A /* WorkspaceDocument+Find.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A53A7D2B4449870093BF8A /* WorkspaceDocument+Find.swift */; }; 61A53A812B4449F00093BF8A /* WorkspaceDocument+Index.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A53A802B4449F00093BF8A /* WorkspaceDocument+Index.swift */; }; + 61C7E82F2C6CDBA500845336 /* Theme+FuzzySearchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C7E82E2C6CDBA500845336 /* Theme+FuzzySearchable.swift */; }; 61FB03AC2C3C1FDF001B3671 /* ShellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FB03AB2C3C1FDF001B3671 /* ShellTests.swift */; }; 61FB03AE2C3C2493001B3671 /* CEActiveTaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FB03AD2C3C2493001B3671 /* CEActiveTaskTests.swift */; }; 61FB03B02C3C76AF001B3671 /* TaskManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FB03AF2C3C76AF001B3671 /* TaskManagerTests.swift */; }; @@ -990,6 +991,7 @@ 61A3E3E62C33383100076BD3 /* EnvironmentVariableListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentVariableListItem.swift; sourceTree = ""; }; 61A53A7D2B4449870093BF8A /* WorkspaceDocument+Find.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WorkspaceDocument+Find.swift"; sourceTree = ""; }; 61A53A802B4449F00093BF8A /* WorkspaceDocument+Index.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WorkspaceDocument+Index.swift"; sourceTree = ""; }; + 61C7E82E2C6CDBA500845336 /* Theme+FuzzySearchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+FuzzySearchable.swift"; sourceTree = ""; }; 61D435CB2C29699800D032B8 /* TaskManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskManager.swift; sourceTree = ""; }; 61D435CD2C2969C300D032B8 /* CEActiveTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CEActiveTask.swift; sourceTree = ""; }; 61D435D12C2969D800D032B8 /* CETaskStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CETaskStatus.swift; sourceTree = ""; }; @@ -3302,6 +3304,22 @@ path = Settings; sourceTree = ""; }; + B6966A262C2F673A00259C2D /* Views */ = { + isa = PBXGroup; + children = ( + B6BF41412C2C672A003AB4B3 /* SourceControlPushView.swift */, + B6966A272C2F683300259C2D /* SourceControlPullView.swift */, + B607184B2B17E037009CDAB4 /* SourceControlStashView.swift */, + B6966A292C2F687A00259C2D /* SourceControlFetchView.swift */, + B67431CB2C3E45F30047FCA6 /* SourceControlSwitchView.swift */, + B65B10F42B081A0C002852CF /* SourceControlAddExistingRemoteView.swift */, + 041FC6AC2AE437CE00C1F65A /* SourceControlNewBranchView.swift */, + B60718362B170638009CDAB4 /* SourceControlRenameBranchView.swift */, + B6966A2F2C33282200259C2D /* RemoteBranchPicker.swift */, + ); + path = Views; + sourceTree = ""; + }; B69D3EDC2C5E856F005CF43A /* Views */ = { isa = PBXGroup; children = ( @@ -3320,22 +3338,6 @@ path = Models; sourceTree = ""; }; - B6966A262C2F673A00259C2D /* Views */ = { - isa = PBXGroup; - children = ( - B6BF41412C2C672A003AB4B3 /* SourceControlPushView.swift */, - B6966A272C2F683300259C2D /* SourceControlPullView.swift */, - B607184B2B17E037009CDAB4 /* SourceControlStashView.swift */, - B6966A292C2F687A00259C2D /* SourceControlFetchView.swift */, - B67431CB2C3E45F30047FCA6 /* SourceControlSwitchView.swift */, - B65B10F42B081A0C002852CF /* SourceControlAddExistingRemoteView.swift */, - 041FC6AC2AE437CE00C1F65A /* SourceControlNewBranchView.swift */, - B60718362B170638009CDAB4 /* SourceControlRenameBranchView.swift */, - B6966A2F2C33282200259C2D /* RemoteBranchPicker.swift */, - ); - path = Views; - sourceTree = ""; - }; B6AB09AB2AAACBF70003A3A6 /* Tabs */ = { isa = PBXGroup; children = ( @@ -3492,6 +3494,7 @@ B6EA1FE429DA33DB001BF195 /* ThemeModel.swift */, B624232F2C21EE280096668B /* ThemeModel+CRUD.swift */, B6EA1FE629DA341D001BF195 /* Theme.swift */, + 61C7E82E2C6CDBA500845336 /* Theme+FuzzySearchable.swift */, ); path = Models; sourceTree = ""; @@ -4146,6 +4149,7 @@ 30AB4EBD2BF71CA800ED4431 /* DeveloperSettingsView.swift in Sources */, 6C6BD6EF29CD12E900235D17 /* ExtensionManagerWindow.swift in Sources */, 30B087FF2C0D53080063A882 /* LanguageServer+Completion.swift in Sources */, + 61C7E82F2C6CDBA500845336 /* Theme+FuzzySearchable.swift in Sources */, 6CFF967629BEBCD900182D6F /* FileCommands.swift in Sources */, B60718462B17DC15009CDAB4 /* RepoOutlineGroupItem.swift in Sources */, 613899B32B6E6FEE00A5CAF6 /* FuzzySearchable.swift in Sources */, diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/Models/Theme+FuzzySearchable.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/Models/Theme+FuzzySearchable.swift new file mode 100644 index 000000000..88826b20f --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/Models/Theme+FuzzySearchable.swift @@ -0,0 +1,14 @@ +// +// Theme+FuzzySearchable.swift +// CodeEdit +// +// Created by Tommy Ludwig on 14.08.24. +// + +import Foundation + +extension Theme: FuzzySearchable { + var searchableString: String { + return id + } +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index 3f327b43e..37ccb1515 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -18,6 +18,8 @@ struct ThemeSettingsView: View { var useDarkTerminalAppearance @State private var listView: Bool = false + @State private var themeSearchQuery: String = "" + @State private var filteredThemes: [Theme] = [] var body: some View { SettingsForm { @@ -41,23 +43,14 @@ struct ThemeSettingsView: View { .labelsHidden() .padding(10) } + + TextField("Search Themes", text: $themeSearchQuery) + .textFieldStyle(.roundedBorder) + .padding(.bottom, 10) + .padding(.horizontal, 10) + VStack(spacing: 0) { - ForEach( - themeModel.selectedAppearance == .dark - ? themeModel.darkThemes - : themeModel.lightThemes - ) { theme in - Divider().padding(.horizontal, 10) - ThemeSettingsThemeRow( - theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], - active: themeModel.getThemeActive(theme) - ).id(theme) - } - ForEach( - themeModel.selectedAppearance == .dark - ? themeModel.lightThemes - : themeModel.darkThemes - ) { theme in + ForEach(filteredThemes) { theme in Divider().padding(.horizontal, 10) ThemeSettingsThemeRow( theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], @@ -94,8 +87,32 @@ struct ThemeSettingsView: View { } )) } + } + .onAppear { + updateFilteredThemes() + } + .onChange(of: themeSearchQuery) { _ in + updateFilteredThemes() + } + .onChange(of: themeModel.selectedAppearance) { _ in + updateFilteredThemes() + } + } + private func updateFilteredThemes() { + var themes: [Theme] = if themeModel.selectedAppearance == .dark { + themeModel.darkThemes + themeModel.lightThemes + } else { + themeModel.lightThemes + themeModel.darkThemes } + + Task { + filteredThemes = themeSearchQuery.isEmpty ? themes : await filterAndSortThemes(themes) + } + } + + private func filterAndSortThemes(_ themes: [Theme]) async -> [Theme] { + return await themes.fuzzySearch(query: themeSearchQuery).map { $1 } } } From 87496996cf617d138ed2fb7fed172cfb50b58c9b Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Sun, 25 Aug 2024 20:02:14 +0200 Subject: [PATCH 2/9] Use Toggle to sort Themes --- .../ThemeSettings/ThemeSettingsView.swift | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index 37ccb1515..1f4c075e0 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -32,22 +32,27 @@ struct ThemeSettingsView: View { } Section { VStack(spacing: 0) { - if settings.matchAppearance { - Picker("", selection: $themeModel.selectedAppearance) { - ForEach(ThemeModel.ThemeSettingsAppearances.allCases, id: \.self) { tab in - Text(tab.rawValue) - .tag(tab) + HStack { + TextField("Search Themes", text: $themeSearchQuery) + .textFieldStyle(.roundedBorder) + + Button { + withAnimation { + themeModel.selectedAppearance = themeModel.selectedAppearance == .dark ? .light : .dark } + } label: { +// Image(systemName: "arrow.up.arrow.down") +// .rotationEffect(.degrees(themeModel.selectedAppearance == .dark ? 0 : 180)) +// .animation(.easeInOut, value: themeModel.selectedAppearance) + Image( + systemName: themeModel.selectedAppearance == .dark ? + "moon.circle.fill" : "sun.max.circle" + ).font(.title2) } - .pickerStyle(.segmented) - .labelsHidden() - .padding(10) + .buttonStyle(.icon) } - - TextField("Search Themes", text: $themeSearchQuery) - .textFieldStyle(.roundedBorder) - .padding(.bottom, 10) - .padding(.horizontal, 10) + .padding(10) + .padding(.leading, 10) VStack(spacing: 0) { ForEach(filteredThemes) { theme in From c5b6c1ed81c7384da7b17bff42eb5f01f629d28c Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Mon, 2 Sep 2024 22:23:19 +0200 Subject: [PATCH 3/9] Fix textfield style --- CodeEdit.xcodeproj/project.pbxproj | 4 + .../ThemeSettings/ThemeSearchField.swift | 58 +++++++ .../ThemeSettings/ThemeSettingsView.swift | 162 ++++++++++-------- 3 files changed, 157 insertions(+), 67 deletions(-) create mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index a39171efc..41407c0ef 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -319,6 +319,7 @@ 617DB3DA2C25B07F00B58BFE /* TaskNotificationsDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617DB3D92C25B07F00B58BFE /* TaskNotificationsDetailView.swift */; }; 617DB3DC2C25B14A00B58BFE /* ActivityViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617DB3DB2C25B14A00B58BFE /* ActivityViewer.swift */; }; 617DB3DF2C25E13800B58BFE /* TaskNotificationHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617DB3DE2C25E13800B58BFE /* TaskNotificationHandlerTests.swift */; }; + 61816B832C81DC2C00C71BF7 /* ThemeSearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61816B822C81DC2C00C71BF7 /* ThemeSearchField.swift */; }; 618725A12C29EFCC00987354 /* SchemeDropDownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618725A02C29EFCC00987354 /* SchemeDropDownView.swift */; }; 618725A42C29F00400987354 /* WorkspaceMenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618725A32C29F00400987354 /* WorkspaceMenuItemView.swift */; }; 618725A62C29F02500987354 /* DropdownMenuItemStyleModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618725A52C29F02500987354 /* DropdownMenuItemStyleModifier.swift */; }; @@ -978,6 +979,7 @@ 617DB3D92C25B07F00B58BFE /* TaskNotificationsDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskNotificationsDetailView.swift; sourceTree = ""; }; 617DB3DB2C25B14A00B58BFE /* ActivityViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityViewer.swift; sourceTree = ""; }; 617DB3DE2C25E13800B58BFE /* TaskNotificationHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskNotificationHandlerTests.swift; sourceTree = ""; }; + 61816B822C81DC2C00C71BF7 /* ThemeSearchField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSearchField.swift; sourceTree = ""; }; 618725A02C29EFCC00987354 /* SchemeDropDownView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchemeDropDownView.swift; sourceTree = ""; }; 618725A32C29F00400987354 /* WorkspaceMenuItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceMenuItemView.swift; sourceTree = ""; }; 618725A52C29F02500987354 /* DropdownMenuItemStyleModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownMenuItemStyleModifier.swift; sourceTree = ""; }; @@ -2469,6 +2471,7 @@ children = ( B6F0518D29DA29F900D72287 /* Models */, 58F2EAAF292FB2B0004A9BDE /* ThemeSettingsView.swift */, + 61816B822C81DC2C00C71BF7 /* ThemeSearchField.swift */, B6EA1FF729DB78DB001BF195 /* ThemeSettingThemeRow.swift */, B6EA1FFA29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift */, B6EA1FFC29DB792C001BF195 /* ThemeSettingsColorPreview.swift */, @@ -4252,6 +4255,7 @@ 6C97EBCC2978760400302F95 /* AcknowledgementsWindowController.swift in Sources */, 284DC84F2978B7B400BF2770 /* ContributorsView.swift in Sources */, B62AEDC92A2704F3009A9F52 /* UtilityAreaTabView.swift in Sources */, + 61816B832C81DC2C00C71BF7 /* ThemeSearchField.swift in Sources */, 30B088052C0D53080063A882 /* LanguageServer+DocumentLink.swift in Sources */, 58798250292E78D80085B254 /* CodeFileDocument.swift in Sources */, 5878DAA5291AE76700DD95A3 /* OpenQuicklyView.swift in Sources */, diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift new file mode 100644 index 000000000..2df783925 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift @@ -0,0 +1,58 @@ +// +// ThemeSearchField.swift +// CodeEdit +// +// Created by Tommy Ludwig on 30.08.24. +// + +import SwiftUI + +struct ThemeSearchField: View { + @Binding var themeSearchQuery: String + var body: some View { + VStack { + HStack(alignment: .top) { + Image(systemName: "magnifyingglass") + .padding(.leading, 2) + .padding(.trailing, -7) + + TextField("", text: $themeSearchQuery) + .textFieldStyle(PlainTextFieldStyle()) + .multilineTextAlignment(.leading) + .overlay { + HStack { + Text("Search") + .foregroundStyle(.secondary) + .opacity(themeSearchQuery.isEmpty ? 1 : 0) + .padding(.leading, 6.5) + + Spacer() + } + } + } + .padding(3) + .overlay( + RoundedRectangle(cornerRadius: 5) + .foregroundStyle(.secondary) +// .blendMode(.overlay) + .blendMode(.difference) + .opacity(0.1) + ) + .overlay { + RoundedRectangle(cornerRadius: 5) + .stroke(Color.gray, lineWidth: 1) + .foregroundStyle(.secondary) + .opacity(0.2) + } +// TextField(text: $themeSearchQuery, prompt: Text("Search")) { +// Label("Test", systemImage: "magnifyingglass") +// } +// .textFieldStyle(.roundedBorder) +// .padding() + } + } +} + +#Preview { + ThemeSearchField(themeSearchQuery: .constant("Test")) +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index 1f4c075e0..c6ccfb0d8 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -22,85 +22,113 @@ struct ThemeSettingsView: View { @State private var filteredThemes: [Theme] = [] var body: some View { - SettingsForm { - Section { - changeThemeOnSystemAppearance - if settings.matchAppearance { - alwaysUseDarkTerminalAppearance - } - useThemeBackground - } - Section { - VStack(spacing: 0) { - HStack { - TextField("Search Themes", text: $themeSearchQuery) - .textFieldStyle(.roundedBorder) + VStack { + Form { + Form { + Section { + HStack { + ThemeSearchField(themeSearchQuery: $themeSearchQuery) + + Button { - Button { - withAnimation { - themeModel.selectedAppearance = themeModel.selectedAppearance == .dark ? .light : .dark + } label: { + Image(systemName: "plus") + } + + Button { + + } label: { + Image(systemName: "ellipsis") } - } label: { -// Image(systemName: "arrow.up.arrow.down") -// .rotationEffect(.degrees(themeModel.selectedAppearance == .dark ? 0 : 180)) -// .animation(.easeInOut, value: themeModel.selectedAppearance) - Image( - systemName: themeModel.selectedAppearance == .dark ? - "moon.circle.fill" : "sun.max.circle" - ).font(.title2) } - .buttonStyle(.icon) } - .padding(10) - .padding(.leading, 10) + } + .formStyle(.columns) - VStack(spacing: 0) { - ForEach(filteredThemes) { theme in - Divider().padding(.horizontal, 10) - ThemeSettingsThemeRow( - theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], - active: themeModel.getThemeActive(theme) - ).id(theme) + if themeSearchQuery.isEmpty { + Section { + changeThemeOnSystemAppearance + if settings.matchAppearance { + alwaysUseDarkTerminalAppearance } + useThemeBackground } } - .padding(-10) - } footer: { - HStack { - Spacer() - Button("Import...") { - themeModel.importTheme() + + Section { + VStack(spacing: 0) { + // HStack { + // TextField("Search Themes", text: $themeSearchQuery) + // .textFieldStyle(.roundedBorder) + // + // Button { + // withAnimation { + // themeModel.selectedAppearance = themeModel.selectedAppearance == .dark ? .light : .dark + // } + // } label: { + //// Image(systemName: "arrow.up.arrow.down") + //// .rotationEffect(.degrees(themeModel.selectedAppearance == .dark ? 0 : 180)) + //// .animation(.easeInOut, value: themeModel.selectedAppearance) + // Image( + // systemName: themeModel.selectedAppearance == .dark ? + // "moon.circle.fill" : "sun.max.circle" + // ).font(.title2) + // } + // .buttonStyle(.icon) + // } + // .padding(10) + // .padding(.leading, 10) + + VStack(spacing: 0) { + ForEach(filteredThemes) { theme in + Divider().padding(.horizontal, 10) + ThemeSettingsThemeRow( + theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], + active: themeModel.getThemeActive(theme) + ).id(theme) + } + } } - } - .padding(.top, 10) - } - } - .sheet(item: $themeModel.detailsTheme) { - themeModel.isAdding = false - } content: { theme in - if let index = themeModel.themes.firstIndex(where: { - $0.fileURL?.absoluteString == theme.fileURL?.absoluteString - }) { - ThemeSettingsThemeDetails(theme: Binding( - get: { themeModel.themes[index] }, - set: { newValue in - themeModel.themes[index] = newValue - themeModel.save(newValue) - if settings.selectedTheme == theme.name { - themeModel.activateTheme(newValue) + .padding(-10) + } footer: { + HStack { + Spacer() + Button("Import...") { + themeModel.importTheme() } } - )) + .padding(.top, 10) + } + .sheet(item: $themeModel.detailsTheme) { + themeModel.isAdding = false + } content: { theme in + if let index = themeModel.themes.firstIndex(where: { + $0.fileURL?.absoluteString == theme.fileURL?.absoluteString + }) { + ThemeSettingsThemeDetails(theme: Binding( + get: { themeModel.themes[index] }, + set: { newValue in + themeModel.themes[index] = newValue + themeModel.save(newValue) + if settings.selectedTheme == theme.name { + themeModel.activateTheme(newValue) + } + } + )) + } + } + .onAppear { + updateFilteredThemes() + } + .onChange(of: themeSearchQuery) { _ in + updateFilteredThemes() + } + .onChange(of: themeModel.selectedAppearance) { _ in + updateFilteredThemes() + } + } - } - .onAppear { - updateFilteredThemes() - } - .onChange(of: themeSearchQuery) { _ in - updateFilteredThemes() - } - .onChange(of: themeModel.selectedAppearance) { _ in - updateFilteredThemes() + .formStyle(.grouped) } } From 2dab6c25daab91eb3289e8e5882aa068b041e6a4 Mon Sep 17 00:00:00 2001 From: Austin Condiff Date: Tue, 3 Sep 2024 10:53:34 -0500 Subject: [PATCH 4/9] Cleaned up theme search UI. --- CodeEdit.xcodeproj/project.pbxproj | 8 +-- .../CodeEditUI/Views/SearchField.swift | 51 +++++++++++++++ .../ThemeSettings/ThemeSearchField.swift | 58 ----------------- .../ThemeSettings/ThemeSettingsView.swift | 63 +++++-------------- 4 files changed, 72 insertions(+), 108 deletions(-) create mode 100644 CodeEdit/Features/CodeEditUI/Views/SearchField.swift delete mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 41407c0ef..a5314dc11 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -319,7 +319,7 @@ 617DB3DA2C25B07F00B58BFE /* TaskNotificationsDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617DB3D92C25B07F00B58BFE /* TaskNotificationsDetailView.swift */; }; 617DB3DC2C25B14A00B58BFE /* ActivityViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617DB3DB2C25B14A00B58BFE /* ActivityViewer.swift */; }; 617DB3DF2C25E13800B58BFE /* TaskNotificationHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617DB3DE2C25E13800B58BFE /* TaskNotificationHandlerTests.swift */; }; - 61816B832C81DC2C00C71BF7 /* ThemeSearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61816B822C81DC2C00C71BF7 /* ThemeSearchField.swift */; }; + 61816B832C81DC2C00C71BF7 /* SearchField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61816B822C81DC2C00C71BF7 /* SearchField.swift */; }; 618725A12C29EFCC00987354 /* SchemeDropDownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618725A02C29EFCC00987354 /* SchemeDropDownView.swift */; }; 618725A42C29F00400987354 /* WorkspaceMenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618725A32C29F00400987354 /* WorkspaceMenuItemView.swift */; }; 618725A62C29F02500987354 /* DropdownMenuItemStyleModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618725A52C29F02500987354 /* DropdownMenuItemStyleModifier.swift */; }; @@ -979,7 +979,7 @@ 617DB3D92C25B07F00B58BFE /* TaskNotificationsDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskNotificationsDetailView.swift; sourceTree = ""; }; 617DB3DB2C25B14A00B58BFE /* ActivityViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityViewer.swift; sourceTree = ""; }; 617DB3DE2C25E13800B58BFE /* TaskNotificationHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskNotificationHandlerTests.swift; sourceTree = ""; }; - 61816B822C81DC2C00C71BF7 /* ThemeSearchField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSearchField.swift; sourceTree = ""; }; + 61816B822C81DC2C00C71BF7 /* SearchField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchField.swift; sourceTree = ""; }; 618725A02C29EFCC00987354 /* SchemeDropDownView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchemeDropDownView.swift; sourceTree = ""; }; 618725A32C29F00400987354 /* WorkspaceMenuItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceMenuItemView.swift; sourceTree = ""; }; 618725A52C29F02500987354 /* DropdownMenuItemStyleModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownMenuItemStyleModifier.swift; sourceTree = ""; }; @@ -2031,6 +2031,7 @@ B67DB0FB2AFDF71F002DC647 /* IconToggleStyle.swift */, 587B9D8D29300ABD00AC7927 /* SearchPanel.swift */, 6CABB1A029C5593800340467 /* SearchPanelView.swift */, + 61816B822C81DC2C00C71BF7 /* SearchField.swift */, 587B9D8929300ABD00AC7927 /* PanelDivider.swift */, B67DB0EE2AF3E381002DC647 /* PaneTextField.swift */, 587B9D8E29300ABD00AC7927 /* PressActionsModifier.swift */, @@ -2471,7 +2472,6 @@ children = ( B6F0518D29DA29F900D72287 /* Models */, 58F2EAAF292FB2B0004A9BDE /* ThemeSettingsView.swift */, - 61816B822C81DC2C00C71BF7 /* ThemeSearchField.swift */, B6EA1FF729DB78DB001BF195 /* ThemeSettingThemeRow.swift */, B6EA1FFA29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift */, B6EA1FFC29DB792C001BF195 /* ThemeSettingsColorPreview.swift */, @@ -4255,7 +4255,7 @@ 6C97EBCC2978760400302F95 /* AcknowledgementsWindowController.swift in Sources */, 284DC84F2978B7B400BF2770 /* ContributorsView.swift in Sources */, B62AEDC92A2704F3009A9F52 /* UtilityAreaTabView.swift in Sources */, - 61816B832C81DC2C00C71BF7 /* ThemeSearchField.swift in Sources */, + 61816B832C81DC2C00C71BF7 /* SearchField.swift in Sources */, 30B088052C0D53080063A882 /* LanguageServer+DocumentLink.swift in Sources */, 58798250292E78D80085B254 /* CodeFileDocument.swift in Sources */, 5878DAA5291AE76700DD95A3 /* OpenQuicklyView.swift in Sources */, diff --git a/CodeEdit/Features/CodeEditUI/Views/SearchField.swift b/CodeEdit/Features/CodeEditUI/Views/SearchField.swift new file mode 100644 index 000000000..ed6c8e2c7 --- /dev/null +++ b/CodeEdit/Features/CodeEditUI/Views/SearchField.swift @@ -0,0 +1,51 @@ +// +// SearchField.swift +// CodeEdit +// +// Created by Austin Condiff on 9/3/24. +// + +import SwiftUI + +struct SearchField: NSViewRepresentable { + @Binding var text: String + var placeholder: String + + init(_ placeholder: String, text: Binding) { + self.placeholder = placeholder + self._text = text + } + + func makeNSView(context: Context) -> NSSearchField { + let searchField = NSSearchField() + searchField.delegate = context.coordinator + searchField.placeholderString = placeholder + return searchField + } + + func updateNSView(_ nsView: NSSearchField, context: Context) { + nsView.stringValue = text + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, NSSearchFieldDelegate { + var parent: SearchField + + init(_ parent: SearchField) { + self.parent = parent + } + + func controlTextDidChange(_ obj: Notification) { + if let searchField = obj.object as? NSSearchField { + parent.text = searchField.stringValue + } + } + } +} + +#Preview { + SearchField("Search", text: .constant("Test")) +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift deleted file mode 100644 index 2df783925..000000000 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSearchField.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// ThemeSearchField.swift -// CodeEdit -// -// Created by Tommy Ludwig on 30.08.24. -// - -import SwiftUI - -struct ThemeSearchField: View { - @Binding var themeSearchQuery: String - var body: some View { - VStack { - HStack(alignment: .top) { - Image(systemName: "magnifyingglass") - .padding(.leading, 2) - .padding(.trailing, -7) - - TextField("", text: $themeSearchQuery) - .textFieldStyle(PlainTextFieldStyle()) - .multilineTextAlignment(.leading) - .overlay { - HStack { - Text("Search") - .foregroundStyle(.secondary) - .opacity(themeSearchQuery.isEmpty ? 1 : 0) - .padding(.leading, 6.5) - - Spacer() - } - } - } - .padding(3) - .overlay( - RoundedRectangle(cornerRadius: 5) - .foregroundStyle(.secondary) -// .blendMode(.overlay) - .blendMode(.difference) - .opacity(0.1) - ) - .overlay { - RoundedRectangle(cornerRadius: 5) - .stroke(Color.gray, lineWidth: 1) - .foregroundStyle(.secondary) - .opacity(0.2) - } -// TextField(text: $themeSearchQuery, prompt: Text("Search")) { -// Label("Test", systemImage: "magnifyingglass") -// } -// .textFieldStyle(.roundedBorder) -// .padding() - } - } -} - -#Preview { - ThemeSearchField(themeSearchQuery: .constant("Test")) -} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index c6ccfb0d8..a533c12ae 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -23,28 +23,24 @@ struct ThemeSettingsView: View { var body: some View { VStack { - Form { - Form { - Section { - HStack { - ThemeSearchField(themeSearchQuery: $themeSearchQuery) + SettingsForm { + Section { + HStack { + SearchField("Search", text: $themeSearchQuery) - Button { + Button { - } label: { - Image(systemName: "plus") - } + } label: { + Image(systemName: "plus") + } - Button { + Button { - } label: { - Image(systemName: "ellipsis") - } + } label: { + Image(systemName: "ellipsis") } } } - .formStyle(.columns) - if themeSearchQuery.isEmpty { Section { changeThemeOnSystemAppearance @@ -57,36 +53,12 @@ struct ThemeSettingsView: View { Section { VStack(spacing: 0) { - // HStack { - // TextField("Search Themes", text: $themeSearchQuery) - // .textFieldStyle(.roundedBorder) - // - // Button { - // withAnimation { - // themeModel.selectedAppearance = themeModel.selectedAppearance == .dark ? .light : .dark - // } - // } label: { - //// Image(systemName: "arrow.up.arrow.down") - //// .rotationEffect(.degrees(themeModel.selectedAppearance == .dark ? 0 : 180)) - //// .animation(.easeInOut, value: themeModel.selectedAppearance) - // Image( - // systemName: themeModel.selectedAppearance == .dark ? - // "moon.circle.fill" : "sun.max.circle" - // ).font(.title2) - // } - // .buttonStyle(.icon) - // } - // .padding(10) - // .padding(.leading, 10) - - VStack(spacing: 0) { - ForEach(filteredThemes) { theme in - Divider().padding(.horizontal, 10) - ThemeSettingsThemeRow( - theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], - active: themeModel.getThemeActive(theme) - ).id(theme) - } + ForEach(filteredThemes) { theme in + Divider().padding(.horizontal, 10) + ThemeSettingsThemeRow( + theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], + active: themeModel.getThemeActive(theme) + ).id(theme) } } .padding(-10) @@ -128,7 +100,6 @@ struct ThemeSettingsView: View { } } - .formStyle(.grouped) } } From a234620e32fa9fe04482dde574de84ab3a2dbc80 Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Fri, 6 Sep 2024 20:37:28 +0200 Subject: [PATCH 5/9] I HATE SwiftUI - Add functionality for the plus button - Add menu (still not working) --- .../ThemeSettings/ThemeSettingsView.swift | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index a533c12ae..d6766a223 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -29,16 +29,32 @@ struct ThemeSettingsView: View { SearchField("Search", text: $themeSearchQuery) Button { - + // As disscussed the expected behaivour would be to duplicate the selected theme + if let selectedTheme = themeModel.selectedTheme { + if let fileURL = selectedTheme.fileURL { + themeModel.duplicate(fileURL) + } + } } label: { Image(systemName: "plus") - } - - Button { + }.disabled(themeModel.selectedTheme == nil) + Menu { + Button { + themeModel.importTheme() + } label: { + Text("Import Theme...") + } + Button { + // TODO + } label: { + Text("Export All Custom Themes...") + } } label: { Image(systemName: "ellipsis") } + .menuStyle(.borderedButton) + .frame(width: 50) } } if themeSearchQuery.isEmpty { @@ -50,7 +66,6 @@ struct ThemeSettingsView: View { useThemeBackground } } - Section { VStack(spacing: 0) { ForEach(filteredThemes) { theme in From 9841228016ce22a3631d12d014d5984fe41231a5 Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Sun, 8 Sep 2024 14:02:03 +0200 Subject: [PATCH 6/9] Add `MenuWithButtonStyle` for a Consistent User Experience --- CodeEdit.xcodeproj/project.pbxproj | 4 ++ .../Views/MenuWithButtonStyle.swift | 33 ++++++++++++++++ .../ThemeSettings/ThemeSettingsView.swift | 38 ++++++++++--------- 3 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 CodeEdit/Features/CodeEditUI/Views/MenuWithButtonStyle.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index a5314dc11..1f36a6a21 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -286,6 +286,7 @@ 5B698A162B263BCE00DE9392 /* SearchSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B698A152B263BCE00DE9392 /* SearchSettingsModel.swift */; }; 5C4BB1E128212B1E00A92FB2 /* World.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4BB1E028212B1E00A92FB2 /* World.swift */; }; 610C0FDA2B44438F00A01CA7 /* WorkspaceDocument+FindAndReplace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 610C0FD92B44438F00A01CA7 /* WorkspaceDocument+FindAndReplace.swift */; }; + 611028C82C8DC7F200DFD845 /* MenuWithButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611028C72C8DC7F100DFD845 /* MenuWithButtonStyle.swift */; }; 611191FA2B08CC9000D4459B /* SearchIndexer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611191F92B08CC9000D4459B /* SearchIndexer.swift */; }; 611191FC2B08CCB800D4459B /* SearchIndexer+AsyncController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611191FB2B08CCB800D4459B /* SearchIndexer+AsyncController.swift */; }; 611191FE2B08CCD200D4459B /* SearchIndexer+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611191FD2B08CCD200D4459B /* SearchIndexer+File.swift */; }; @@ -949,6 +950,7 @@ 5B698A152B263BCE00DE9392 /* SearchSettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsModel.swift; sourceTree = ""; }; 5C4BB1E028212B1E00A92FB2 /* World.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = World.swift; sourceTree = ""; }; 610C0FD92B44438F00A01CA7 /* WorkspaceDocument+FindAndReplace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WorkspaceDocument+FindAndReplace.swift"; sourceTree = ""; }; + 611028C72C8DC7F100DFD845 /* MenuWithButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuWithButtonStyle.swift; sourceTree = ""; }; 611191F92B08CC9000D4459B /* SearchIndexer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchIndexer.swift; sourceTree = ""; }; 611191FB2B08CCB800D4459B /* SearchIndexer+AsyncController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SearchIndexer+AsyncController.swift"; sourceTree = ""; }; 611191FD2B08CCD200D4459B /* SearchIndexer+File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SearchIndexer+File.swift"; sourceTree = ""; }; @@ -2032,6 +2034,7 @@ 587B9D8D29300ABD00AC7927 /* SearchPanel.swift */, 6CABB1A029C5593800340467 /* SearchPanelView.swift */, 61816B822C81DC2C00C71BF7 /* SearchField.swift */, + 611028C72C8DC7F100DFD845 /* MenuWithButtonStyle.swift */, 587B9D8929300ABD00AC7927 /* PanelDivider.swift */, B67DB0EE2AF3E381002DC647 /* PaneTextField.swift */, 587B9D8E29300ABD00AC7927 /* PressActionsModifier.swift */, @@ -4198,6 +4201,7 @@ 30AB4EBB2BF718A100ED4431 /* DeveloperSettings.swift in Sources */, B6C4F2A92B3CB00100B2B140 /* CommitDetailsHeaderView.swift in Sources */, 30B088012C0D53080063A882 /* LanguageServer+Definition.swift in Sources */, + 611028C82C8DC7F200DFD845 /* MenuWithButtonStyle.swift in Sources */, B6EA1FFB29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift in Sources */, 618725A62C29F02500987354 /* DropdownMenuItemStyleModifier.swift in Sources */, 587B9E7029301D8F00AC7927 /* GitLabUser.swift in Sources */, diff --git a/CodeEdit/Features/CodeEditUI/Views/MenuWithButtonStyle.swift b/CodeEdit/Features/CodeEditUI/Views/MenuWithButtonStyle.swift new file mode 100644 index 000000000..2e432354f --- /dev/null +++ b/CodeEdit/Features/CodeEditUI/Views/MenuWithButtonStyle.swift @@ -0,0 +1,33 @@ +// +// MenuWithButtonStyle.swift +// CodeEdit +// +// Created by Tommy Ludwig on 08.09.24. +// + +import SwiftUI + +/// A menu styled to resemble a bordered button. +struct MenuWithButtonStyle: View { + var systemImage: String + var menu: () -> MenuView + var body: some View { + Menu { menu() } label: {} + .background { + Button {} label: { + HStack { + Image(systemName: systemImage) + Image(systemName: "chevron.down") + .resizable() + .fontWeight(.bold) + .frame(width: 8, height: 4.8) + .padding(.leading, -1.5) + .padding(.trailing, -2) + }.offset(y: 1) + } + } + .menuStyle(.borderlessButton) + .menuIndicator(.hidden) + .frame(width: 30) + } +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index d6766a223..64b303f34 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -25,11 +25,11 @@ struct ThemeSettingsView: View { VStack { SettingsForm { Section { - HStack { + HStack(spacing: 10) { SearchField("Search", text: $themeSearchQuery) Button { - // As disscussed the expected behaivour would be to duplicate the selected theme + // As discussed, the expected behavior is to duplicate the selected theme. if let selectedTheme = themeModel.selectedTheme { if let fileURL = selectedTheme.fileURL { themeModel.duplicate(fileURL) @@ -37,24 +37,26 @@ struct ThemeSettingsView: View { } } label: { Image(systemName: "plus") - }.disabled(themeModel.selectedTheme == nil) + } + .disabled(themeModel.selectedTheme == nil) + .help("Create a new Theme") - Menu { - Button { - themeModel.importTheme() - } label: { - Text("Import Theme...") - } - Button { - // TODO - } label: { - Text("Export All Custom Themes...") + MenuWithButtonStyle(systemImage: "ellipsis", menu: { + Group { + Button { + themeModel.importTheme() + } label: { + Text("Import Theme...") + } + Button { + // TODO: #1873 + } label: { + Text("Export All Custom Themes...") + }.disabled(true) } - } label: { - Image(systemName: "ellipsis") - } - .menuStyle(.borderedButton) - .frame(width: 50) + }) + .padding(.horizontal, 5) + .help("Import or Export Custom Themes") } } if themeSearchQuery.isEmpty { From 6c86de2ed2beb655e4d4319ebe9a1c9036057113 Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Sun, 8 Sep 2024 14:20:36 +0200 Subject: [PATCH 7/9] Re-sort themes on system color scheme change --- .../ThemeSettings/ThemeSettingsView.swift | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index 64b303f34..d2fcc6a02 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -112,20 +112,24 @@ struct ThemeSettingsView: View { .onChange(of: themeSearchQuery) { _ in updateFilteredThemes() } - .onChange(of: themeModel.selectedAppearance) { _ in - updateFilteredThemes() + .onChange(of: colorScheme) { newColorScheme in + updateFilteredThemes(overrideColorScheme: newColorScheme) } - } } } - private func updateFilteredThemes() { - var themes: [Theme] = if themeModel.selectedAppearance == .dark { - themeModel.darkThemes + themeModel.lightThemes - } else { - themeModel.lightThemes + themeModel.darkThemes - } + /// Sorts themes by `colorScheme` and `themeSearchQuery`. + /// Dark mode themes appear before light themes if in dark mode, and vice versa. + private func updateFilteredThemes(overrideColorScheme: ColorScheme? = nil) { + // This check is necessary because, when calling `updateFilteredThemes` from within the + // `onChange` handler that monitors the `colorScheme`, there are cases where the function + // is invoked with outdated values of `colorScheme`. + let isDarkScheme = overrideColorScheme ?? colorScheme == .dark + + let themes: [Theme] = isDarkScheme + ? (themeModel.darkThemes + themeModel.lightThemes) + : (themeModel.lightThemes + themeModel.darkThemes) Task { filteredThemes = themeSearchQuery.isEmpty ? themes : await filterAndSortThemes(themes) From 480589f8bbbaa6b6d918dfd566780b8bd788518f Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Sun, 8 Sep 2024 14:29:56 +0200 Subject: [PATCH 8/9] Update ThemeSettingsView.swift --- .../Settings/Pages/ThemeSettings/ThemeSettingsView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index d2fcc6a02..a05ef9291 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -49,7 +49,7 @@ struct ThemeSettingsView: View { Text("Import Theme...") } Button { - // TODO: #1873 + // TODO: #1874 } label: { Text("Export All Custom Themes...") }.disabled(true) From a5febc267ddf5fef91196e02f67c74f2f9c1c4c1 Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Sat, 14 Sep 2024 17:26:00 +0200 Subject: [PATCH 9/9] Fix unexpected nil error --- .../Pages/ThemeSettings/ThemeSettingsView.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index a05ef9291..49371070a 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -71,11 +71,13 @@ struct ThemeSettingsView: View { Section { VStack(spacing: 0) { ForEach(filteredThemes) { theme in - Divider().padding(.horizontal, 10) - ThemeSettingsThemeRow( - theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], - active: themeModel.getThemeActive(theme) - ).id(theme) + if let themeIndex = themeModel.themes.firstIndex(of: theme) { + Divider().padding(.horizontal, 10) + ThemeSettingsThemeRow( + theme: $themeModel.themes[themeIndex], + active: themeModel.getThemeActive(theme) + ).id(theme) + } } } .padding(-10)