Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for parameters #3

Merged
merged 3 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ excluded:
- "*resource_bundle_accessor*" # SwiftPM Generated
- ".build/*"

disabled_rules:
- todo

opt_in_rules:
- missing_docs
- empty_count
Expand Down
9 changes: 6 additions & 3 deletions Playground/DynamicUI Playground/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@ struct ContentView: View {
"children": [
{
"type": "Button",
"title": "Click me"
"title": "Click me",
"eventHandler": "customHandler"
},
{
"type": "Toggle",
"title": "Toggle me"
"title": "Toggle me",
"identifier": "my.toggle.1"
},
{
"type": "Text",
"title": "_Wait_, am i generating views from JSON?"
"title": "_Wait_, am i generating views from JSON?",
"modifiers": {"foregroundStyle":"red","opacity":0.5},
},
{
"type": "Label",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import SwiftUI

@main
struct DynamicUI_PlaygroundApp: App {
struct DynamicUIPlaygroundApp: App {
var body: some Scene {
WindowGroup {
ContentView()
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,29 @@ struct ContentView: View {
[
{
"type": "Text",
"title": "Wait, am i generating views from JSON?"
"title": "Wait, am i generating views from JSON?",
"modifiers": {"foregroundStyle":"red","opacity":0.6}
},
{
"type": "Button",
"title": "Click me",
"eventHandler": "customHandler"
},
{
"type": "Toggle",
"title": "Toggle me",
"identifier": "my.toggle.1"
}
]
""".data(using: .utf8)

var body: some View {
DynamicUI(
json: json
json: json,
callback: { component in
// This contains everything passed as a component (type, title, identifier, ...)
print(component)
}
)
}
}
Expand Down
1 change: 1 addition & 0 deletions Sources/DynamicUI/DynamicUI.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//
//
// DynamicUI.swift
// DynamicUI
//
Expand Down
8 changes: 4 additions & 4 deletions Sources/DynamicUI/DynamicUIComponent.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// UIComponent.swift
// DynamicUIComponent.swift
// DynamicUI
//
// Created by Wesley de Groot on 16/04/2024.
Expand Down Expand Up @@ -38,11 +38,11 @@ public struct DynamicUIComponent: Codable, Hashable {
/// Default value of component
public let defaultValue: AnyCodable?

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

/// Parameters of component (not yet used)
public let parameters: [[String: AnyCodable]]?
public let parameters: [String: AnyCodable]?

/// Image URL
public let imageURL: String?
Expand Down
2 changes: 2 additions & 0 deletions Sources/DynamicUI/Extensions/Binding.onChange.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import SwiftUI

extension Binding {
/// On Change of a Binding value
///
/// - Parameter handler: Callback handler
///
/// - Returns: Binding
func onChange(_ callback: @escaping (Value) -> Void) -> Binding<Value> {
Binding(
Expand Down
79 changes: 79 additions & 0 deletions Sources/DynamicUI/Extensions/View.modifiers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// Modifiers.swift
// DynamicUI
//
// Created by Wesley de Groot on 25/07/2024.
// https://wesleydegroot.nl
//
// https://github.com/0xWDG/DynamicUI
// MIT LICENCE

import SwiftUI

extension View {
/// DynamicUIModifiers
///
/// This function adds modifiers to a DynamicUIView
///
/// - Parameter modifiers: The modifiers to apply
///
/// - Returns: The modified view
public func dynamicUIModifiers(_ modifiers: [String: AnyCodable]?) -> some View {
// swiftlint:disable:previous cyclomatic_complexity
guard let modifiers = modifiers else {
return AnyView(self)
}

let helper = DynamicUIHelper()
var tempView = AnyView(self)

modifiers.forEach { key, value in
switch key {
case "foregroundStyle":
guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *),
let string = value.toString(),
let color = helper.translateColor(string) else { break }
tempView = AnyView(tempView.foregroundStyle(color))

case "backgroundStyle":
guard #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *),
let string = value.toString(),
let color = helper.translateColor(string) else { break }
tempView = AnyView(tempView.backgroundStyle(color))

case "fontWeight":
guard #available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *),
let string = value.toString(),
let weight = helper.translateFontWeight(string) else { break }
tempView = AnyView(tempView.fontWeight(weight))

case "font":
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) else { break }
tempView = AnyView(tempView.font(.none))

case "frame":
// guard let color:
// minWidth: <#0#>, idealWidth: <#100#>, maxWidth: <#.infinity#>,
// minHeight: <#0#>, idealHeight: <#100#>, maxHeight: <#.infinity#>, alignment: <#.center#>)
// width: <#0#> height: <#0#>
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) else { break }
tempView = AnyView(tempView.frame())

case "padding":
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *),
let length = value.toInt() else { break }
tempView = AnyView(tempView.padding(CGFloat(integerLiteral: length)))

case "opacity":
guard #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *),
let opacity = value.toDouble() else { break }
tempView = AnyView(tempView.opacity(opacity))

default:
break
}
}

return tempView
}
}
140 changes: 140 additions & 0 deletions Sources/DynamicUI/Helpers/DynamicUIHelper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//
// DynamicUIHelper.swift
// DynamicUI
//
// Created by Wesley de Groot on 25/07/2024.
// https://wesleydegroot.nl
//
// https://github.com/0xWDG/DynamicUI
// MIT LICENCE

import SwiftUI

// swiftlint:disable cyclomatic_complexity function_body_length
/// DynamicUIHelper
///
/// DynamicUIHelper helps to translate Strings to native SwiftUI .context
public class DynamicUIHelper {

/// Translate string colors to native ``Color``.
///
/// - Parameter input: Color as string
///
/// - Returns: SwiftUI ``Color``
public func translateColor(_ input: String) -> Color? {
switch input.lowercased() {
case "red":
return .red

case "orange":
return .orange

case "yellow":
return .yellow

case "green":
return .green

case "mint":
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
return .mint
}
return .primary

case "teal":
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
return .teal
}
return .primary

case "cyan":
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
return .cyan
}
return .primary

case "blue":
return .blue

case "indigo":
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
return .indigo
}
return .primary

case "purple":
return .purple

case "pink":
return .pink

case "brown":
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
return .brown
}
return .primary

case "white":
return .white

case "gray":
return .gray

case "black":
return .black

case "clear":
return .clear

case "primary":
return .primary

case "secondary":
return .secondary

default:
return .primary
}
}

/// Translate a string font weight to a native ``Font.Weight``
///
/// - Parameter input: Font weight as string
///
/// - Returns: Translated ``Font.Weight``
func translateFontWeight(_ input: String) -> Font.Weight? {
switch input {
case "ultraLight":
return .ultraLight

case "thin":
return .thin

case "light":
return .light

case "regular":
return .regular

case "medium":
return .medium

case "semibold":
return .semibold

case "bold":
return .bold

case "heavy":
return .heavy

case "black":
return .black

default:
return .regular
}
}
}

// swiftlint:enable cyclomatic_complexity function_body_length
6 changes: 5 additions & 1 deletion Sources/DynamicUI/Views/DynamicButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import SwiftUI
/// ```json
/// {
/// "type": "Button",
/// "title": "Title"
/// "title": "Title",
/// "modifiers": {
/// "foregroundColor": "blue"
/// }
/// }
/// ```
///
Expand Down Expand Up @@ -49,5 +52,6 @@ public struct DynamicButton: View {
}, label: {
Text(component.title ?? "Button")
})
.dynamicUIModifiers(component.modifiers)
}
}
5 changes: 3 additions & 2 deletions Sources/DynamicUI/Views/DynamicDisclosureGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import SwiftUI
/// DynamicUI: DisclosureGroup
///
/// DynamicDisclosureGroup is a SwiftUI View that can be used to display an DisclosureGroup.
///
///
/// JSON Example:
/// ```json
/// {
/// "type": "DisclosureGroup",
/// "children": [ ]
/// }
/// ```
///
///
/// - Note: This is a internal view, you should not use this directly. \
/// Use ``DynamicUI`` instead. this function is public to generate documentation.
public struct DynamicDisclosureGroup: View {
Expand All @@ -45,6 +45,7 @@ public struct DynamicDisclosureGroup: View {
AnyView(dynamicUIEnvironment.buildView(for: children))
}
}
.dynamicUIModifiers(component.modifiers)
#else
DynamicVStack(component)
#endif
Expand Down
1 change: 1 addition & 0 deletions Sources/DynamicUI/Views/DynamicDivider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ public struct DynamicDivider: View {
/// Generated body for SwiftUI
public var body: some View {
Divider()
.dynamicUIModifiers(component.modifiers)
}
}
3 changes: 2 additions & 1 deletion Sources/DynamicUI/Views/DynamicForm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ public struct DynamicForm: View {

/// Generated body for SwiftUI
public var body: some View {
Form {
Form {
if let children = component.children {
AnyView(dynamicUIEnvironment.buildView(for: children))
}
}
.dynamicUIModifiers(component.modifiers)
}
}
Loading
Loading