CardBuilder.swift 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. //
  2. // CardBuilder.swift
  3. // LoopKitUI
  4. //
  5. // Created by Michael Pangburn on 4/15/20.
  6. // Copyright © 2020 LoopKit Authors. All rights reserved.
  7. //
  8. import SwiftUI
  9. /// A function builder designed to construct a `Card`.
  10. ///
  11. /// Transformations are applied as follows:
  12. /// - An expression conforming to `View` becomes one component of one card.
  13. /// - An instance of `Splat` is unrolled into a dynamic number of components within one card.
  14. ///
  15. /// Any number of components (individual or splatted) can be sequenced and combined into a single card.
  16. @resultBuilder
  17. public struct CardBuilder {
  18. public typealias Component = Card
  19. public static func buildIf(_ component: Component?) -> Component {
  20. // If `nil` (i.e. a condition is `false`), leave a placeholder `nil` view to enable smooth insertion when the condition becomes `true`.
  21. component ?? Card(parts: [nil])
  22. }
  23. public static func buildBlock<V: View>(_ v: V) -> Component {
  24. toCard(v)
  25. }
  26. public static func buildBlock<V0: View, V1: View>(_ v0: V0, _ v1: V1) -> Component {
  27. Card(reducing: [toCard(v0), toCard(v1)])
  28. }
  29. public static func buildBlock<V0: View, V1: View, V2: View>(_ v0: V0, _ v1: V1, _ v2: V2) -> Component {
  30. Card(reducing: [toCard(v0), toCard(v1), toCard(v2)])
  31. }
  32. public static func buildBlock<V0: View, V1: View, V2: View, V3: View>(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3) -> Component {
  33. Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3)])
  34. }
  35. public static func buildBlock<V0: View, V1: View, V2: View, V3: View, V4: View>(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4) -> Component {
  36. Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4)])
  37. }
  38. public static func buildBlock<V0: View, V1: View, V2: View, V3: View, V4: View, V5: View>(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5) -> Component {
  39. Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5)])
  40. }
  41. public static func buildBlock<V0: View, V1: View, V2: View, V3: View, V4: View, V5: View, V6: View>(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6) -> Component {
  42. Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6)])
  43. }
  44. public static func buildBlock<V0: View, V1: View, V2: View, V3: View, V4: View, V5: View, V6: View, V7: View>(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7) -> Component {
  45. Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6), toCard(v7)])
  46. }
  47. public static func buildBlock<V0: View, V1: View, V2: View, V3: View, V4: View, V5: View, V6: View, V7: View, V8: View>(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7, _ v8: V8) -> Component {
  48. Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6), toCard(v7), toCard(v8)])
  49. }
  50. public static func buildBlock<V0: View, V1: View, V2: View, V3: View, V4: View, V5: View, V6: View, V7: View, V8: View, V9: View>(_ v0: V0, _ v1: V1, _ v2: V2, _ v3: V3, _ v4: V4, _ v5: V5, _ v6: V6, _ v7: V7, _ v8: V8, _ v9: V9) -> Component {
  51. Card(reducing: [toCard(v0), toCard(v1), toCard(v2), toCard(v3), toCard(v4), toCard(v5), toCard(v6), toCard(v7), toCard(v8), toCard(v9)])
  52. }
  53. // TODO: Simplify using `buildExpression` when Swift 5.2 is available.
  54. private static func toCard<V: View>(_ v: V) -> Card {
  55. if let card = v as? Card {
  56. return card
  57. } else if let splat = v as? Splat {
  58. return Card(components: [.dynamic(splat.identifiedViews)])
  59. } else {
  60. return Card(components: [.static(AnyView(v))])
  61. }
  62. }
  63. }