From c7b90e148dc7417bd83fde14b253a21e51996e9a Mon Sep 17 00:00:00 2001 From: dfowj Date: Wed, 24 Jun 2026 15:04:11 -0400 Subject: [PATCH 1/3] Relax constraints on ConfigVariableEditor's custom content --- App/Sources/App/ContentView.swift | 15 ++++-- .../ConfigVariableListView.swift | 23 +++------ .../Editor/ConfigVariableEditor.swift | 49 +++---------------- 3 files changed, 26 insertions(+), 61 deletions(-) diff --git a/App/Sources/App/ContentView.swift b/App/Sources/App/ContentView.swift index 17b6b43..5c1685f 100644 --- a/App/Sources/App/ContentView.swift +++ b/App/Sources/App/ContentView.swift @@ -27,11 +27,18 @@ struct ContentView: View { } .sheet(isPresented: $isPresentingConfigEditor) { ConfigVariableEditor( - reader: viewModel.configVariableReader, - customSectionTitle: "Actions", + reader: viewModel.configVariableReader ) { - Button("Do something", role: .destructive) { - print("Did something!") + Section("First Section") { + Button("Do something") { + print("Did something!") + } + } + + Section("Second Section") { + Button("Do something else", role: .destructive) { + print("Did something else!") + } } } dismiss: { variables in print(variables) diff --git a/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift b/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift index 080039f..f093853 100644 --- a/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift +++ b/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift @@ -17,14 +17,11 @@ import SwiftUI /// variable's detail view. /// /// The toolbar provides Cancel, Save, and an overflow menu with Undo, Redo, and Clear Editor Overrides actions. -struct ConfigVariableListView: View { +struct ConfigVariableListView: View { @State var viewModel: ViewModel - /// The title for the custom section at the top of the list. - private let customSectionTitle: Text - /// The custom section content to display at the top of the list. - private let customSection: CustomSection + private let customContent: CustomContent @Environment(\.dismiss) private var dismiss @@ -33,24 +30,18 @@ struct ConfigVariableListView CustomSection) { + /// - customContent: A view builder that produces custom content to display in a section at the top of the list. + init(viewModel: ViewModel, @ViewBuilder customContent: () -> CustomContent) { self._viewModel = State(initialValue: viewModel) - self.customSectionTitle = customSectionTitle - self.customSection = customSection() + self.customContent = customContent() } var body: some View { NavigationStack { List { - if CustomSection.self != EmptyView.self { - Section { - customSection - } header: { - customSectionTitle - } + if CustomContent.self != EmptyView.self { + customContent } Section(localizedStringResource("editorView.variablesSection.header")) { diff --git a/Sources/DevConfiguration/Editor/ConfigVariableEditor.swift b/Sources/DevConfiguration/Editor/ConfigVariableEditor.swift index 8ba8e57..e61f3d0 100644 --- a/Sources/DevConfiguration/Editor/ConfigVariableEditor.swift +++ b/Sources/DevConfiguration/Editor/ConfigVariableEditor.swift @@ -33,40 +33,12 @@ import SwiftUI /// } dismiss: { changedVariables in /// // Handle changed variables and dismiss /// } -public struct ConfigVariableEditor: View { +public struct ConfigVariableEditor: View { /// The list view model created from the reader. @State private var viewModel: ConfigVariableListViewModel? - /// The title for the custom section. - private let customSectionTitle: Text - /// The custom section content. - private let customSection: CustomSection - - - /// Creates a new configuration variable editor with a custom section at the top of the list. - /// - /// - Parameters: - /// - reader: The configuration variable reader. If the reader was not created with `isEditorEnabled` set to - /// `true`, the view is empty. - /// - customSectionTitle: The title for the custom section. - /// - customSection: A view builder that produces custom content to display in a section at the top of the list. - /// - dismiss: An optional closure called when the editor is dismissed. It receives the registered variables whose - /// overrides changed, or an empty array if dismissed without saving. If `nil`, the environment's dismiss action - /// is used. - public init( - reader: ConfigVariableReader, - customSectionTitle: LocalizedStringKey, - @ViewBuilder customSection: () -> CustomSection, - dismiss: (([RegisteredConfigVariable]) -> Void)? = nil, - ) { - self.init( - reader: reader, - customSectionTitle: Text(customSectionTitle), - customSection: customSection, - dismiss: dismiss, - ) - } + private let customContent: CustomContent /// Creates a new configuration variable editor with a custom section at the top of the list. @@ -74,19 +46,16 @@ public struct ConfigVariableEditor: View { /// - Parameters: /// - reader: The configuration variable reader. If the reader was not created with `isEditorEnabled` set to /// `true`, the view is empty. - /// - customSectionTitle: A `Text` view to use as the title for the custom section. - /// - customSection: A view builder that produces custom content to display in a section at the top of the list. + /// - customContent: A view builder that produces custom content to display in a section at the top of the list. /// - dismiss: An optional closure called when the editor is dismissed. It receives the registered variables whose /// overrides changed, or an empty array if dismissed without saving. If `nil`, the environment's dismiss action /// is used. public init( reader: ConfigVariableReader, - customSectionTitle: Text, - @ViewBuilder customSection: () -> CustomSection, + @ViewBuilder customContent: () -> CustomContent, dismiss: (([RegisteredConfigVariable]) -> Void)? = nil, ) { - self.customSectionTitle = customSectionTitle - self.customSection = customSection() + self.customContent = customContent() self._viewModel = Self.makeViewModel(reader: reader, dismiss: dismiss) } @@ -95,8 +64,7 @@ public struct ConfigVariableEditor: View { if let viewModel { ConfigVariableListView( viewModel: viewModel, - customSectionTitle: customSectionTitle, - customSection: { customSection }, + customContent: { customContent }, ) } } @@ -127,7 +95,7 @@ public struct ConfigVariableEditor: View { } -extension ConfigVariableEditor where CustomSection == EmptyView { +extension ConfigVariableEditor where CustomContent == EmptyView { /// Creates a new configuration variable editor. /// /// - Parameters: @@ -140,8 +108,7 @@ extension ConfigVariableEditor where CustomSection == EmptyView { reader: ConfigVariableReader, dismiss: (([RegisteredConfigVariable]) -> Void)? = nil, ) { - self.customSectionTitle = Text(verbatim: "") - self.customSection = EmptyView() + self.customContent = EmptyView() self._viewModel = Self.makeViewModel(reader: reader, dismiss: dismiss) } } From ff0dfbbe23d4ca7e80ec4b5b8898cb80d6e0b031 Mon Sep 17 00:00:00 2001 From: dfowj Date: Wed, 24 Jun 2026 15:39:27 -0400 Subject: [PATCH 2/3] Update Changelog.md, back-dated for previous releases --- CHANGELOG.md | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb586d3..b845549 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,107 @@ # DevConfiguration Changelog -## 1.0.0 – TBD +## 1.0.0: TBD Description forthcoming. + + +## 0.12.0: TBD + +This release contains **breaking changes** to the configuration variable editor’s custom content API. + + - `ConfigVariableEditor` no longer takes a `customSectionTitle` parameter. Instead, the `customContent` view + builder is responsible for providing its own `Section` views (or other list content). + - The `customSection` view builder parameter has been renamed to `customContent`. + +If you previously presented the editor with a custom section title and content, move the section title into a +`Section` view inside `customContent`. + + +## 0.11.0: April 13, 2026 + +This release adds a confirm keyboard button on the variable detail screen so that users who edit numeric types can +actually commit the edit. + + +## 0.10.1: April 5, 2026 + +This release only contains small fixes in the project’s DocC documentation. + + +## 0.10.0: March 30, 2026 + +This is a tiny release that simply exports Configuration so that consumers don’t have to import both +DevConfiguration and Configuration. + + +## 0.9.0: March 29, 2026 + +This release makes the following changes: + + - `ConfigVariableEditor` now takes an optional `dismiss` closure instead of an `onSave` closure. This closure takes + an array of modified variables just like `onSave`. However, if the `dismiss` closure is provided, it is the + caller’s responsibility to dismiss the editor. If no closure is provided, the editor will use the environment’s + dismiss action. + - The `requiresRelaunch` config variable metadata key has been removed. In general, consumers should try to + respond to variable changes at runtime. If this is not possible, you can create your own similar metadata key. + + +## 0.8.1: March 19, 2026 + +This is a small release that updates to DevFoundation 1.8.1 and makes `RegisteredConfigVariable`’s metadata +subscript public. + + +## 0.8.0: March 17, 2026 + +This is a small release that sorts metadata keys on the variable detail view of the editor. + + +## 0.7.0: March 17, 2026 + +This release adds the `isEditable` metadata value to config variables. When `false`, a config variable will not be +editable in the Config Variable Editor. `true` by default. + + +## 0.6.0: March 11, 2026 + +This release enhances the editor UI to show pickers for `CaseIterable` integers and strings, allow editing arrays +and JSON payloads in text editors, and handle formatting better for scalar types. + + +## 0.5.0: March 10, 2026 + +This release adds the ability for consumers to add a custom section to the config variable editor. + + +## 0.4.1: March 10, 2026 + +This release fixes a bug in which editor overrides were read from one UserDefaults instance, but saved to another. + + +## 0.4.0: March 10, 2026 + +This release adds a configuration editor written in SwiftUI. The editor allows consumers to view registered variable +values in a list, see the values of a variables across all the different providers, override values for development +and testing, and view variable metadata values. + +The UI has only meaningfully been tested on iOS. It has not been accessibility tested. + + +## 0.3.0: March 10, 2026 + +This is a small release that updates `ConfigVariableReader` from a struct to a class to make variable registration +easier for consumers. + + +## 0.2.0: March 10, 2026 + +Adds the ability to register variables with `ConfigVariableReader`. This functionality is not yet used, but sets up +the public interface for consumers. + + +## 0.1.0: March 10, 2026 + +Initial version of DevConfiguration with the ability to read variables, with scalar, array, `RawRepresentable`, and +`Codable` types. Also emits access telemetry on the event bus. From 24cb0e5f2c45c74dd69037c08afe7593e9af108c Mon Sep 17 00:00:00 2001 From: dfowj Date: Wed, 24 Jun 2026 15:51:48 -0400 Subject: [PATCH 3/3] Remove "section" mentions throughout documentation. --- .../Config Variable List/ConfigVariableListView.swift | 6 ++---- .../DevConfiguration/Editor/ConfigVariableEditor.swift | 9 ++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift b/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift index f093853..17879a4 100644 --- a/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift +++ b/Sources/DevConfiguration/Editor/Config Variable List/ConfigVariableListView.swift @@ -20,7 +20,7 @@ import SwiftUI struct ConfigVariableListView: View { @State var viewModel: ViewModel - /// The custom section content to display at the top of the list. + /// The custom content to display at the top of the list. private let customContent: CustomContent @Environment(\.dismiss) private var dismiss @@ -40,9 +40,7 @@ struct ConfigVariableListView: View { /// The list view model created from the reader. @State private var viewModel: ConfigVariableListViewModel? - /// The custom section content. + /// The custom content. private let customContent: CustomContent - /// Creates a new configuration variable editor with a custom section at the top of the list. + /// Creates a new configuration variable editor with custom content at the top of the list. /// /// - Parameters: /// - reader: The configuration variable reader. If the reader was not created with `isEditorEnabled` set to