Skip to content

Commit c545f89

Browse files
authored
Merge pull request #3 from 0xWDG/feature/support-parameters
Initial support for parameters
2 parents cd2f6b9 + 749490a commit c545f89

36 files changed

+308
-32
lines changed

.swiftlint.yml

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ excluded:
22
- "*resource_bundle_accessor*" # SwiftPM Generated
33
- ".build/*"
44

5+
disabled_rules:
6+
- todo
7+
58
opt_in_rules:
69
- missing_docs
710
- empty_count

Playground/DynamicUI Playground/ContentView.swift

+6-3
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,18 @@ struct ContentView: View {
2020
"children": [
2121
{
2222
"type": "Button",
23-
"title": "Click me"
23+
"title": "Click me",
24+
"eventHandler": "customHandler"
2425
},
2526
{
2627
"type": "Toggle",
27-
"title": "Toggle me"
28+
"title": "Toggle me",
29+
"identifier": "my.toggle.1"
2830
},
2931
{
3032
"type": "Text",
31-
"title": "_Wait_, am i generating views from JSON?"
33+
"title": "_Wait_, am i generating views from JSON?",
34+
"modifiers": {"foregroundStyle":"red","opacity":0.5},
3235
},
3336
{
3437
"type": "Label",

Playground/DynamicUI Playground/DynamicUI_PlaygroundApp.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import SwiftUI
99

1010
@main
11-
struct DynamicUI_PlaygroundApp: App {
11+
struct DynamicUIPlaygroundApp: App {
1212
var body: some Scene {
1313
WindowGroup {
1414
ContentView()

README.md

+17-2
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,29 @@ struct ContentView: View {
4848
[
4949
{
5050
"type": "Text",
51-
"title": "Wait, am i generating views from JSON?"
51+
"title": "Wait, am i generating views from JSON?",
52+
"modifiers": {"foregroundStyle":"red","opacity":0.6}
53+
},
54+
{
55+
"type": "Button",
56+
"title": "Click me",
57+
"eventHandler": "customHandler"
58+
},
59+
{
60+
"type": "Toggle",
61+
"title": "Toggle me",
62+
"identifier": "my.toggle.1"
5263
}
5364
]
5465
""".data(using: .utf8)
5566

5667
var body: some View {
5768
DynamicUI(
58-
json: json
69+
json: json,
70+
callback: { component in
71+
// This contains everything passed as a component (type, title, identifier, ...)
72+
print(component)
73+
}
5974
)
6075
}
6176
}

Sources/DynamicUI/DynamicUI.swift

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//
2+
//
23
// DynamicUI.swift
34
// DynamicUI
45
//

Sources/DynamicUI/DynamicUIComponent.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// UIComponent.swift
2+
// DynamicUIComponent.swift
33
// DynamicUI
44
//
55
// Created by Wesley de Groot on 16/04/2024.
@@ -38,11 +38,11 @@ public struct DynamicUIComponent: Codable, Hashable {
3838
/// Default value of component
3939
public let defaultValue: AnyCodable?
4040

41-
/// Styling of components (not yet used)
42-
public let styling: [[String: AnyCodable]]?
41+
/// Modifiers to components (not yet used)
42+
public let modifiers: [String: AnyCodable]?
4343

4444
/// Parameters of component (not yet used)
45-
public let parameters: [[String: AnyCodable]]?
45+
public let parameters: [String: AnyCodable]?
4646

4747
/// Image URL
4848
public let imageURL: String?

Sources/DynamicUI/Extensions/Binding.onChange.swift

+2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import SwiftUI
1212

1313
extension Binding {
1414
/// On Change of a Binding value
15+
///
1516
/// - Parameter handler: Callback handler
17+
///
1618
/// - Returns: Binding
1719
func onChange(_ callback: @escaping (Value) -> Void) -> Binding<Value> {
1820
Binding(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//
2+
// Modifiers.swift
3+
// DynamicUI
4+
//
5+
// Created by Wesley de Groot on 25/07/2024.
6+
// https://wesleydegroot.nl
7+
//
8+
// https://github.com/0xWDG/DynamicUI
9+
// MIT LICENCE
10+
11+
import SwiftUI
12+
13+
extension View {
14+
/// DynamicUIModifiers
15+
///
16+
/// This function adds modifiers to a DynamicUIView
17+
///
18+
/// - Parameter modifiers: The modifiers to apply
19+
///
20+
/// - Returns: The modified view
21+
public func dynamicUIModifiers(_ modifiers: [String: AnyCodable]?) -> some View {
22+
// swiftlint:disable:previous cyclomatic_complexity
23+
guard let modifiers = modifiers else {
24+
return AnyView(self)
25+
}
26+
27+
let helper = DynamicUIHelper()
28+
var tempView = AnyView(self)
29+
30+
modifiers.forEach { key, value in
31+
switch key {
32+
case "foregroundStyle":
33+
guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *),
34+
let string = value.toString(),
35+
let color = helper.translateColor(string) else { break }
36+
tempView = AnyView(tempView.foregroundStyle(color))
37+
38+
case "backgroundStyle":
39+
guard #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *),
40+
let string = value.toString(),
41+
let color = helper.translateColor(string) else { break }
42+
tempView = AnyView(tempView.backgroundStyle(color))
43+
44+
case "fontWeight":
45+
guard #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *),
46+
let string = value.toString(),
47+
let weight = helper.translateFontWeight(string) else { break }
48+
tempView = AnyView(tempView.fontWeight(weight))
49+
50+
case "font":
51+
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) else { break }
52+
tempView = AnyView(tempView.font(.none))
53+
54+
case "frame":
55+
// guard let color:
56+
// minWidth: <#0#>, idealWidth: <#100#>, maxWidth: <#.infinity#>,
57+
// minHeight: <#0#>, idealHeight: <#100#>, maxHeight: <#.infinity#>, alignment: <#.center#>)
58+
// width: <#0#> height: <#0#>
59+
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) else { break }
60+
tempView = AnyView(tempView.frame())
61+
62+
case "padding":
63+
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *),
64+
let length = value.toInt() else { break }
65+
tempView = AnyView(tempView.padding(CGFloat(integerLiteral: length)))
66+
67+
case "opacity":
68+
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *),
69+
let opacity = value.toDouble() else { break }
70+
tempView = AnyView(tempView.opacity(opacity))
71+
72+
default:
73+
break
74+
}
75+
}
76+
77+
return tempView
78+
}
79+
}
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//
2+
// DynamicUIHelper.swift
3+
// DynamicUI
4+
//
5+
// Created by Wesley de Groot on 25/07/2024.
6+
// https://wesleydegroot.nl
7+
//
8+
// https://github.com/0xWDG/DynamicUI
9+
// MIT LICENCE
10+
11+
import SwiftUI
12+
13+
// swiftlint:disable cyclomatic_complexity function_body_length
14+
/// DynamicUIHelper
15+
///
16+
/// DynamicUIHelper helps to translate Strings to native SwiftUI .context
17+
public class DynamicUIHelper {
18+
19+
/// Translate string colors to native ``Color``.
20+
///
21+
/// - Parameter input: Color as string
22+
///
23+
/// - Returns: SwiftUI ``Color``
24+
public func translateColor(_ input: String) -> Color? {
25+
switch input.lowercased() {
26+
case "red":
27+
return .red
28+
29+
case "orange":
30+
return .orange
31+
32+
case "yellow":
33+
return .yellow
34+
35+
case "green":
36+
return .green
37+
38+
case "mint":
39+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
40+
return .mint
41+
}
42+
return .primary
43+
44+
case "teal":
45+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
46+
return .teal
47+
}
48+
return .primary
49+
50+
case "cyan":
51+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
52+
return .cyan
53+
}
54+
return .primary
55+
56+
case "blue":
57+
return .blue
58+
59+
case "indigo":
60+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
61+
return .indigo
62+
}
63+
return .primary
64+
65+
case "purple":
66+
return .purple
67+
68+
case "pink":
69+
return .pink
70+
71+
case "brown":
72+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
73+
return .brown
74+
}
75+
return .primary
76+
77+
case "white":
78+
return .white
79+
80+
case "gray":
81+
return .gray
82+
83+
case "black":
84+
return .black
85+
86+
case "clear":
87+
return .clear
88+
89+
case "primary":
90+
return .primary
91+
92+
case "secondary":
93+
return .secondary
94+
95+
default:
96+
return .primary
97+
}
98+
}
99+
100+
/// Translate a string font weight to a native ``Font.Weight``
101+
///
102+
/// - Parameter input: Font weight as string
103+
///
104+
/// - Returns: Translated ``Font.Weight``
105+
func translateFontWeight(_ input: String) -> Font.Weight? {
106+
switch input {
107+
case "ultraLight":
108+
return .ultraLight
109+
110+
case "thin":
111+
return .thin
112+
113+
case "light":
114+
return .light
115+
116+
case "regular":
117+
return .regular
118+
119+
case "medium":
120+
return .medium
121+
122+
case "semibold":
123+
return .semibold
124+
125+
case "bold":
126+
return .bold
127+
128+
case "heavy":
129+
return .heavy
130+
131+
case "black":
132+
return .black
133+
134+
default:
135+
return .regular
136+
}
137+
}
138+
}
139+
140+
// swiftlint:enable cyclomatic_complexity function_body_length

Sources/DynamicUI/Views/DynamicButton.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import SwiftUI
1818
/// ```json
1919
/// {
2020
/// "type": "Button",
21-
/// "title": "Title"
21+
/// "title": "Title",
22+
/// "modifiers": {
23+
/// "foregroundColor": "blue"
24+
/// }
2225
/// }
2326
/// ```
2427
///
@@ -49,5 +52,6 @@ public struct DynamicButton: View {
4952
}, label: {
5053
Text(component.title ?? "Button")
5154
})
55+
.dynamicUIModifiers(component.modifiers)
5256
}
5357
}

Sources/DynamicUI/Views/DynamicDisclosureGroup.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ import SwiftUI
1313
/// DynamicUI: DisclosureGroup
1414
///
1515
/// DynamicDisclosureGroup is a SwiftUI View that can be used to display an DisclosureGroup.
16-
///
16+
///
1717
/// JSON Example:
1818
/// ```json
1919
/// {
2020
/// "type": "DisclosureGroup",
2121
/// "children": [ ]
2222
/// }
2323
/// ```
24-
///
24+
///
2525
/// - Note: This is a internal view, you should not use this directly. \
2626
/// Use ``DynamicUI`` instead. this function is public to generate documentation.
2727
public struct DynamicDisclosureGroup: View {
@@ -45,6 +45,7 @@ public struct DynamicDisclosureGroup: View {
4545
AnyView(dynamicUIEnvironment.buildView(for: children))
4646
}
4747
}
48+
.dynamicUIModifiers(component.modifiers)
4849
#else
4950
DynamicVStack(component)
5051
#endif

Sources/DynamicUI/Views/DynamicDivider.swift

+1
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,6 @@ public struct DynamicDivider: View {
3939
/// Generated body for SwiftUI
4040
public var body: some View {
4141
Divider()
42+
.dynamicUIModifiers(component.modifiers)
4243
}
4344
}

Sources/DynamicUI/Views/DynamicForm.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ public struct DynamicForm: View {
3939

4040
/// Generated body for SwiftUI
4141
public var body: some View {
42-
Form {
42+
Form {
4343
if let children = component.children {
4444
AnyView(dynamicUIEnvironment.buildView(for: children))
4545
}
4646
}
47+
.dynamicUIModifiers(component.modifiers)
4748
}
4849
}

0 commit comments

Comments
 (0)