-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds a general solution for debuggable enum parameters. Requires the enum conforms to `CaseIterable, CustomDebugStringConvertible, Hashable`. Uses `debugDescription` for the string displayed in the debug view picker. Shows a picker for selecting enum options in the debug menu. ![Kapture 2022-03-07 at 10 24 41](https://user-images.githubusercontent.com/609274/157094905-806e76ff-ef02-47bf-914d-3b6a724a52a4.gif)
- Loading branch information
Malcolm Jarvis
authored
Mar 8, 2022
1 parent
e193122
commit ed68c81
Showing
5 changed files
with
116 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import Exhibition | ||
import SwiftUI | ||
|
||
struct CustomSegmentedControl: View { | ||
let title: String | ||
@Binding var selection: Option | ||
|
||
var body: some View { | ||
Picker(title, selection: $selection) { | ||
ForEach(Option.allCases, id: \.rawValue) { option in | ||
Text(option.rawValue).tag(option) | ||
} | ||
} | ||
.pickerStyle(SegmentedPickerStyle()) | ||
} | ||
|
||
enum Option: String, CaseIterable, CustomDebugStringConvertible { | ||
case first = "first" | ||
case second = "second" | ||
case third = "third" | ||
|
||
var debugDescription: String { | ||
rawValue | ||
} | ||
} | ||
} | ||
|
||
struct CustomSegmentedControl_Previews: ExhibitProvider, PreviewProvider { | ||
static var exhibit: Exhibit = Exhibit( | ||
name: "CustomSegmentedControl", | ||
section: "Pickers" | ||
) { context in | ||
CustomSegmentedControl( | ||
title: context.parameter(name: "title", defaultValue: "Title"), | ||
selection: context.parameter(name: "selection", defaultValue: .first) | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import SwiftUI | ||
|
||
public extension Context { | ||
/// Helper enum to avoid repetition of protocols below | ||
typealias EnumType = CaseIterable & CustomDebugStringConvertible & Hashable | ||
|
||
/// Create a constant parameter for a selectable Enum | ||
/// - Parameters: | ||
/// - name: The debug description name for the parameter. | ||
/// - defaultValue: The initial case for the enum. | ||
/// - Returns: The currently selected case of the enum | ||
func parameter<E: EnumType>(name: String, defaultValue: E) -> E { | ||
let parameter: EnumParameter = parameter( | ||
name: name, | ||
defaultValue: EnumParameter(value: defaultValue) | ||
) | ||
|
||
return parameter.current as! E | ||
} | ||
|
||
/// Create a binding parameter for a selectable enum | ||
/// - Parameters: | ||
/// - name: The debug description name for the parameter. | ||
/// - defaultValue: The initial case for the enum. | ||
/// - Returns: A binding for the currently selected case of the enum | ||
func parameter<E: EnumType>(name: String, defaultValue: E) -> Binding<E> { | ||
let parameter: Binding<EnumParameter> = parameter( | ||
name: name, | ||
defaultValue: EnumParameter(value: defaultValue) | ||
) | ||
|
||
return Binding( | ||
get: { parameter.wrappedValue.current as! E }, | ||
set: { parameter.wrappedValue.current = $0 } | ||
) | ||
} | ||
} | ||
|
||
/// A parameter representing a selectable Enum | ||
struct EnumParameter { | ||
var current: AnyHashable | ||
let cases: [String: AnyHashable] | ||
|
||
init<E: Context.EnumType>(value: E) { | ||
self.current = value | ||
self.cases = Dictionary(uniqueKeysWithValues: E.allCases.map { | ||
($0.debugDescription, $0) | ||
}) | ||
} | ||
|
||
func value<E>() -> E? { | ||
return current as? E | ||
} | ||
} | ||
|
||
/// Debug parameter row for `EnumParameter` | ||
struct EnumParameterView: ParameterView { | ||
let key: String | ||
@Binding var value: EnumParameter | ||
|
||
public var body: some View { | ||
Picker(key, selection: $value.current) { | ||
ForEach(value.cases.sorted(by: keyAscending), id: \.0) { (key, value) in | ||
Text(key).tag(value) | ||
} | ||
} | ||
} | ||
} |