View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Videos

Abrir menú Cerrar menú
  • Colecciones
  • Todos los videos
  • Información

Más videos

  • Información
  • Código
  • What's new in SwiftUI

    It's a SwiftUI party — and you're invited! Join us as we share the latest updates and a glimpse into the future of UI framework design. Discover deep levels of customization, advanced techniques for layout, elegant strategies for sharing, and rock-solid structural approaches for designing an app top-to-bottom in SwiftUI. We'll also have some celebratory fun as we play with the latest graphical effects and explore APIs.

    Recursos

    • SwiftUI
      • Video HD
      • Video SD

    Videos relacionados

    WWDC22

    • Bring multiple windows to your SwiftUI app
    • Build a productivity app for Apple Watch
    • Compose custom layouts with SwiftUI
    • Enhance collaboration experiences with Messages
    • Hello Swift Charts
    • Integrate your custom collaboration app with Messages
    • Meet Transferable
    • Swift Charts: Raise the bar
    • SwiftUI on iPad: Add toolbars, titles, and more
    • SwiftUI on iPad: Organize your interface
    • The SwiftUI cookbook for navigation
    • Use Xcode to develop a multiplatform app
    • What's new in Xcode
    • What’s new in iPad app design
    • WWDC22 Day 1 recap
  • Buscar este video…
    • 2:51 - Swift Charts: Required models and extensions

      import Foundation
      import SwiftUI
      
      // MARK: - Party Planner Models
      enum PartyTask: String, Identifiable, CaseIterable, Hashable {
          case food = "Food"
          case music = "Music"
          case supplies = "Supplies"
          case invitations = "Invitations"
          case eventDetails = "Event Details"
          case activities = "Activities"
          case funProjection = "Fun Projection"
          case vips = "VIPs"
          case photosFilter = "Photos Filter"
      
          var name: String { rawValue }
        
         var color: Color {
             switch self {
             case .food:
                  return palette[0]
             case .supplies:
                  return palette[1]
             case .invitations:
                  return palette[2]
             case .eventDetails:
                  return palette[3]
             case .funProjection:
                  return palette[4]
             case .activities:
                  return palette[5]
             case .vips:
                  return palette[6]
             case .music:
                  return palette[7]
             case .photosFilter:
                  return palette[8]
             }
          }
      
          var imageName: String {
              switch self {
              case .food:
                  return "birthday.cake"
              case .supplies:
                  return  "party.popper"
              case .invitations:
                  return "envelope.open"
              case .eventDetails:
                  return "calendar.badge.clock"
              case .funProjection:
                  return "gauge.medium"
              case .activities:
                  return "bubbles.and.sparkles"
              case .vips:
                  return "person.2"
              case .music:
                  return  "music.mic"
              case .photosFilter:
                  return "camera.filters"
              }
          }
      
          var id: String { rawValue }
      
          var subtitle: String {
              switch self {
              case .food:
                  return "Apps, 'Zerts and Cakes"
              case .supplies:
                  return "Streamers, Plates, Cups"
              case .invitations:
                  return "Sendable, Non-Transferable"
              case .eventDetails:
                  return "Date, Duration, And Placement"
              case .funProjection:
                  return "Beta — How Fun Will Your Party Be?"
              case .activities:
                  return "Dancing, Paired Programing"
              case .vips:
                  return "User Interactive Guests"
              case .music:
                  return "Song Requests & Karaoke"
              case .photosFilter:
                  return "Filtering and Mapping"
              }
          }
      
          var emoji: String {
              switch self {
              case .food:
                  return "🎂"
              case .music:
                  return "🎤"
              case .supplies:
                  return "🎉"
              case .invitations:
                  return "📨"
              case .eventDetails:
                  return "🗓"
              case .funProjection:
                  return "🧭"
              case .activities:
                  return "💃"
              case .vips:
                  return "⭐️"
              case .photosFilter:
                  return "📸"
              }
          }
      }
      
      private let palette: [Color] = [
          Color(red: 0.73, green: 0.20, blue: 0.20),
          Color(red: 0.95, green: 0.66, blue: 0.24),
          Color(red: 0.14, green: 0.29, blue: 0.49),
          Color(red: 0.46, green: 0.76, blue: 0.67),
          Color(red: 0.30, green: 0.33, blue: 0.22),
          Color(red: 0.49, green: 0.55, blue: 0.64),
          Color(red: 0.92, green: 0.53, blue: 0.30),
          Color(red: 0.20, green: 0.45, blue: 0.55),
          Color(red: 0.41, green: 0.45, blue: 0.45),
          Color(red: 0.87, green: 0.67, blue: 0.61)
      ]
      
      // MARK: - Swift Charts Models
      
      struct RemainingPartyTask: Identifiable {
          let category: PartyTask
          let date: Date
          let remainingCount: Int
      
          let id = UUID()
      }
      
      let remainingSupplies: [RemainingPartyTask] = [
          RemainingPartyTask(category: .supplies, date: .daysAgo(4), remainingCount: 10),
          RemainingPartyTask(category: .supplies, date: .daysAgo(3), remainingCount: 11),
          RemainingPartyTask(category: .supplies, date: .daysAgo(2), remainingCount: 9),
          RemainingPartyTask(category: .supplies, date: .daysAgo(1), remainingCount: 4),
          RemainingPartyTask(category: .supplies, date: .daysAgo(0), remainingCount: 1),
      ]
      
      let remainingInvitations: [RemainingPartyTask] = [
          RemainingPartyTask(category: .invitations, date: .daysAgo(4), remainingCount: 14),
          RemainingPartyTask(category: .invitations, date: .daysAgo(3), remainingCount: 13),
          RemainingPartyTask(category: .invitations, date: .daysAgo(2), remainingCount: 11),
          RemainingPartyTask(category: .invitations, date: .daysAgo(1), remainingCount: 6),
          RemainingPartyTask(category: .invitations, date: .daysAgo(0), remainingCount: 4),
      ]
      
      let remainingActivities: [RemainingPartyTask] = [
          RemainingPartyTask(category: .activities, date: .daysAgo(4), remainingCount: 6),
          RemainingPartyTask(category: .activities, date: .daysAgo(3), remainingCount: 7),
          RemainingPartyTask(category: .activities, date: .daysAgo(2), remainingCount: 4),
          RemainingPartyTask(category: .activities, date: .daysAgo(1), remainingCount: 2),
          RemainingPartyTask(category: .activities, date: .daysAgo(0), remainingCount: 1),
      ]
      
      let remainingVenue: [RemainingPartyTask] = [
          RemainingPartyTask(category: .eventDetails, date: .daysAgo(4), remainingCount: 4),
          RemainingPartyTask(category: .eventDetails, date: .daysAgo(3), remainingCount: 5),
          RemainingPartyTask(category: .eventDetails, date: .daysAgo(2), remainingCount: 7),
          RemainingPartyTask(category: .eventDetails, date: .daysAgo(1), remainingCount: 4),
          RemainingPartyTask(category: .eventDetails, date: .daysAgo(0), remainingCount: 2)
      ]
      
      let partyTasksRemaining: [RemainingPartyTask] = [remainingVenue,
                                                      remainingActivities,
                                                      remainingInvitations,
                                                      remainingSupplies
      ].flatMap { $0 }
      
      // MARK: Date Utilities
      
      extension Date {
          static func daysAgo(_ daysAgo: Int) -> Date {
              Calendar.current.date(byAdding: .day, value: -daysAgo, to: Date())!
          }
      
          func daysEqual(_ other: Date) -> Bool {
              Calendar.current.dateComponents([.day], from: self, to: other).day == 0
          }
      }
      
      extension Date {
          static let wwdc22: Date = DateComponents(
              calendar: .autoupdatingCurrent,
              timeZone: TimeZone(identifier: "PST"),
              year: 2022,
              month: 6,
              day: 6,
              hour: 9,
              minute: 41,
              second: 00).date!
      }
    • 2:56 - Swift Charts: Bar Chart 1

      Chart(partyTasksRemaining) {
          BarMark(
              x: .value("Date", $0.date, unit: .day),
              y: .value("Tasks Remaining", $0.remainingCount)
          )
      }
      .padding()
    • 3:33 - Swift Charts: Bar chart 2

      var body: some View {
          Chart(partyTasksRemaining) {
              BarMark(
                  x: .value("Date", $0.date, unit: .day),
                  y: .value("Tasks Remaining", $0.remainingCount)
              )
          }
          .padding()
      }
    • 3:53 - Swift Charts: LineMark

      var body: some View {
          Chart(partyTasksRemaining) {
              LineMark(
                  x: .value("Date", $0.date, unit: .day),
                  y: .value("Tasks Remaining", $0.remainingCount)
              )
              .foregroundStyle(by: .value("Category", $0.category))
          }
          .padding()
      }
    • 4:08 - Swift Charts: Line Chart with Symbols

      var body: some View {
          Chart(partyTasksRemaining) {
              LineMark(
                  x: .value("Date", $0.date, unit: .day),
                  y: .value("Tasks Remaining", $0.remainingCount)
              )
              .foregroundStyle(by: .value("Category", $0.category))
              .symbol(by: .value("Category", $0.category))
          }
          .padding()
      }
    • 4:39 - Swift Charts: Annotations

      var body: some View {
          Chart {
              ForEach(partyTasksRemaining) { task in
                  LineMark(
                      x: .value("Date", task.date, unit: .day),
                      y: .value("Tasks Remaining", task.remainingCount)
                  )
                  .foregroundStyle(by: .value("Category", task.category))
                  .symbol(by: .value("Category", task.category))
                  .annotation(position: .leading) {
                      Text("\(task.category.emoji)")
                  }
              }
      
              RuleMark(y: .value("Value", 5))
                  .foregroundStyle(.red)
                  .lineStyle(StrokeStyle(lineWidth: 2.0, dash: [4, 5]))
                  .annotation(position: .top, alignment: .trailing) {
                      VStack(alignment: .trailing) {
                          Text("Today's Goal")
                          Text("Status: ✔︎")
                      }
                      .font(.caption)
                      .foregroundColor(.gray)
                      .padding(.trailing, 2)
                  }
          }
      }
    • 6:15 - Food Models

      import Foundation
      
      // MARK: Food Models
      
      /// A model representing a food with a price and quantity.
      struct FoodItem: Hashable, Identifiable, Codable, Equatable {
          let emoji: String
          let name: String
          var description: String = ""
          let price: Decimal
          var quantity: Int = 0
          var id: String { name }
      }
      
      let donut = FoodItem(emoji: "🍩", name: "Doughnut", description: "Yeast, Old-fashioned, Cake, and the dubious Apple Fritter", price: 2.35, quantity: 6)
      let moonCake = FoodItem(emoji: "🥮", name: "Moon Cake", description: "Lotus seed paste — plenty of crust", price: 2.20, quantity: 4)
      let shavedIce = FoodItem(emoji: "🍧", name: "Shaved Ice", description: "Shave your own ice!", price: 3.25, quantity: 1)
      let cupcake = FoodItem(emoji: "🧁", name: "Cupcake", description: "Also goes by the name Cake Nano", price: 4.00, quantity: 5)
      let flan = FoodItem(emoji: "🍮", name: "Flan", description: "What's in a flan? That which we call milk, eggs, and sugar by any other name would taste just as sweet.", price: 6.50, quantity: 2)
      let taffy = FoodItem(emoji: "🍬", name: "Taffy", description: "Freshwater, actually.", price: 1.00, quantity: 11)
      let cake = FoodItem(emoji: "🎂", name: "Cake Cake", description: "The real deal", price: 15.00, quantity: 1)
      let cookie = FoodItem(emoji: "🍪", name: "Cookie Cake", description: "The ultimate dessert", price: 4.30, quantity: 1)
      
      let relatedFoods = [donut, moonCake, shavedIce, cupcake, flan, taffy, cake, cookie]
      
      extension Array where Element: Equatable {
      
          /// A quick-and-dirty way of getting a random few elements from an Array that don't include a single,
          /// particular element.
          /// - Parameters:
          ///   - count: The number of desired random elements, must be less than `Array.count`
          ///   - except: Filter out this particular element    
          func random(_ count: Int, except: Element) -> [Element] {
              assert(count >= count)
              var copy = self
              copy.shuffle()
              copy.removeAll(where: { $0 == except })
              return Array(copy[0..<count])
          }
      }
      
      let partyFoods = [
          FoodItem(emoji: "🍨", name: "Ice Cream",
                   price: 3.50, quantity: 4),
          flan,
          taffy,
          donut,
          FoodItem(emoji: "🍉", name: "Watermelon",
                   price: 3.65, quantity: 1),
          FoodItem(emoji: "🍒", name: "Cherries",
                   price: 8.00, quantity: 1),
          cupcake,
          cookie,
          FoodItem(emoji: "🍥", name: "Fish Cake",
                   price: 5.00, quantity: 2),
          moonCake,
          cake,
          FoodItem(emoji: "🍘", name: "Rice Cracker",
                   price: 0.25, quantity: 16),
          FoodItem(emoji: "🥨", name: "Pretzels",
                   price: 3.00, quantity: 3),
          shavedIce,
          FoodItem(emoji: "🥧", name: "Apple Pie",
                   price: 4.10, quantity: 1)
      ]
    • 6:21 - NavigationStack with view-based NavigationLinks

      // MARK: NavigationStack with View-based NavigationLinks
      
      struct FoodsListView: View {
          fileprivate var foodItems = partyFoods
          @State private var selectedFoodItems: [FoodItem] = []
      
          var body: some View {
              NavigationStack {
                  List(foodItems) { item in
                      NavigationLink {
                          FoodDetailView(item: item)
                      } label: {
                          FoodRow(food: item)
                      }
                  }
                  .navigationTitle("Party Food")
      
              }
          }
      }
      
      struct FoodRow: View {
          let food: FoodItem
      
          var body: some View {
              HStack {
                  Text(food.emoji)
                      .font(.system(size: 15))
                      .foregroundStyle(.secondary)
                  Text(food.name)
                      .font(.caption)
                      .bold()
                  Spacer()
                  Text("\(food.quantity)")
              }
          }
      }
      
      struct FoodDetailView: View {
          let item: FoodItem
      
          var body: some View {
              ScrollView {
                  VStack {
                      HStack {
                          Text(item.emoji)
                              .font(.system(size: 30))
                          Text(item.name)
                              .font(.title3)
                      }
                      .padding(.bottom, 4)
                      Text(item.description)
                          .font(.caption)
                      Divider()
                      RelatedFoodsView(relatedFoods: relatedFoods.random(3, except: item))
                  }
              }
          }
      }
      
      struct RelatedFoodsView: View {
          @State var relatedFoods: [FoodItem]
      
          var body: some View {
              VStack {
                  Text("Related Foods")
                      .background(.background, in: RoundedRectangle(cornerRadius: 2))
                  HStack {
                      ForEach(relatedFoods) { food in                    
                          NavigationLink {
                              FoodDetailView(item: food)
                          } label: { Text(food.emoji) }
                      }
                  }
              }
          }
      }
    • 6:51 - NavigationStack with value-based NavigationLinks

      // MARK: NavigationStack with Value-based Navigation Links
      
      struct FoodsListView: View {
          fileprivate var foodItems = partyFoods
          @State private var selectedFoodItems: [FoodItem] = []
      
          var body: some View {
              NavigationStack(path: $selectedFoodItems) {
                  List(foodItems) { item in
                      NavigationLink(value: item) {
                          FoodRow(food: item)
                      }
                  }
                  .navigationTitle("Party Food")
                  .navigationDestination(for: FoodItem.self) { item in
                      FoodDetailView(item: item, path: $selectedFoodItems)
                  }
              }
          }
      }
      
      struct FoodDetailView: View {
          let item: FoodItem
          @Binding var path: [FoodItem]
      
          var body: some View {
              ScrollView {
                  VStack {
                      HStack {
                          Text(item.emoji)
                              .font(.system(size: 30))
                          Text(item.name)
                              .font(.title3)
                      }
                      .padding(.bottom, 4)
                      Text(item.description)
                          .font(.caption)
                      Divider()
                      RelatedFoodsView(relatedFoods: relatedFoods.random(3, except: item))
                      if path.count > 1 {
                          Button("Back to First Item") { path.removeSubrange(1...) }
                      }
                  }
              }
          }
      }
      
      struct RelatedFoodsView: View {
          @State var relatedFoods: [FoodItem]
      
          var body: some View {
              VStack {
                  Text("Related Foods")
                      .background(.background, in: RoundedRectangle(cornerRadius: 2))
                  HStack {
                      ForEach(relatedFoods) { food in
                          NavigationLink(value: food) {
                              Text(food.emoji)
                          }
                      }
                  }
              }
          }
      }
    • 8:16 - NavigationSplitView

      // MARK: NavigationSplitView Demo
      
      struct PartyPlannerHome: View {
          @State private var selectedTask: PartyTask?
      
          var body: some View {
              NavigationSplitView {
                  List(PartyTask.allCases, selection: $selectedTask) { task in
                      NavigationLink(value: task) {
                          TaskLabel(task: task)
                      }
      						    .listItemTint(task.color)
                  }
              } detail: {
                  selectedTask.flatMap { $0.color } ?? .white
              }
          }
      }
      
      struct TaskLabel: View {
          let task: PartyTask
      
          var body: some View {
              Label {
                  VStack(alignment: .leading) {
                      Text(task.name)
                      Text(task.subtitle)
                          .font(.footnote)
                          .foregroundStyle(.secondary)
                  }
              } icon: {
                  Image(systemName: task.imageName)
                      .symbolVariant(.circle.fill)
              }
          }
      }
    • 9:13 - Navigation split and stack composition

      struct PartyPlannerHome: View {
          @State private var selectedTask: PartyTask?
      
          var body: some View {
              NavigationSplitView {
                  List(PartyTask.allCases, selection: $selectedTask) { task in
                      NavigationLink(value: task) {
                          TaskLabel(task: task)
                      }
                      .listItemTint(task.color)
                  }
              } detail: {
                  if case .food = selectedTask {
                      FoodsListView()
                  } else {
                      selectedTask.flatMap { $0.color } ?? .white
                  }
              }
          }
      }
    • 10:10 - Window

      @main
      struct PartyPlanner: App {
          var body: some Scene {
              WindowGroup("Party Planner") {
                  PartyPlannerHome()
              }
      
              Window("Party Budget", id: "budget") {
                  Text("Budget View")
              }
              .keyboardShortcut("0")
          }
      }
    • 10:42 - Open window

      struct DetailView: View {
          @Environment(\.openWindow) var openWindow
      
          var body: some View {
              Text("Detail View")
                  .toolbar {
                      Button {
                          openWindow(id: "budget")
                      } label: {
                          Image(systemName: "dollarsign")
                      }
                  }
          }
      }
    • 11:00 - Window customizations

      @main
      struct PartyPlanner: App {
          var body: some Scene {
              WindowGroup("Party Planner") {
                  PartyPlannerHome()
              }
      
              Window("Party Budget", id: "budget") {
                  Text("Budget View")
              }
              .keyboardShortcut("0")
              .defaultPosition(.topLeading)
              .defaultSize(width: 220, height: 250)
          }
      }
    • 11:47 - Resizable sheets

      struct PartyPlannerHome: View {
          @State private var selectedTask: PartyTask?
          @State private var presented: Bool = false
      
          var body: some View {
              NavigationSplitView {
                  List(PartyTask.allCases, selection: $selectedTask) { task in
                      NavigationLink(value: task) {
                          TaskLabel(task: task)
                      }
                      .listItemTint(task.color)
                  }
              } detail: {
                  if case .food = selectedTask {
                      FoodsListView()
                  } else {
                      selectedTask.flatMap { $0.color } ?? .white
                  }
              }
              .sheet(isPresented: $presented) {
                  Text("Budget View")
                      .presentationDetents([.height(250), .medium])
                      .presentationDragIndicator(.visible)
              }
          }
      }
    • 12:51 - Menu bar extras

      @main
      struct PartyPlanner: App {
          var body: some Scene {
              Window("Party Budget", id: "budget") {
                  Text("Budget View")
              }
      
              MenuBarExtra("Bulletin Board", systemImage: "quote.bubble") {
                  BulletinBoard()
              }
              .menuBarExtraStyle(.window)
          }
      }
      
      
      
      private let allPosts: [String] = [
          "Did you know: On your third birthday, you are celebrating your 4.0 release.",
      ]
      
      struct BulletinBoard: View {
      
          @State var currentPostIndex: Int = 0
      
          var currentPost: String {
              allPosts[currentPostIndex]
          }
      
          var body: some View {
              VStack(spacing: 16) {
      
                  VStack(spacing: 12) {
                      HStack(alignment: .firstTextBaseline) {
                          Text("“")
                              .font(.custom("Helvetica", size: 50).bold())
                              .baselineOffset(-23)
                              .foregroundStyle(.tertiary)
      
                          Text("Party Bulletin Board")
                              .font(.headline.weight(.semibold))
                              .foregroundStyle(.secondary)
      
                          Spacer()
      
                          Text("June 6, 2022")
                              .font(.headline.weight(.regular))
                              .foregroundStyle(.secondary)
                      }
                      .frame(height: 20)
      
      
                      Text(currentPost)
                          .font(.system(size: 18))
                          .multilineTextAlignment(.center)
                  }
                  .padding(.bottom, 4)
      
                  Divider()
      
                  HStack {
                      Button {
      
                      } label: {
                          Label("Calendar", systemImage: "calendar")
                      }
                      Button {
                          currentPostIndex = (currentPostIndex + 1) % allPosts.count
                      } label: {
                          Text("Previous")
                              .frame(maxWidth: .infinity)
                      }
      
                      ShareLink(items: [currentPost])
                  }
                  .labelStyle(.iconOnly)
                  .controlSize(.large)
              }
              .padding(16)
          }
      }
    • 12:58 - Menu bar extra app

      @main
      struct MessageBoard: App {
          var body: some Scene {
              MenuBarExtra("Bulletin Board", systemImage: "quote.bubble") {
                  BulletinBoard()
              }
              .menuBarExtraStyle(.window)
          }
      }
    • 14:25 - Grouped forms

      struct ContentView: View {
          enum Theme: String, CaseIterable, Identifiable {
              var id: String { self.rawValue }
              case blue, gold, black, white
      
              var swatch: some View {
                  Circle()
                      .fill(color)
                      .overlay {
                          Circle().stroke(.tertiary)
                      }
                      .frame(width: 15, height: 15)
              }
      
              var color: Color {
                  switch self {
                  case .blue: return .blue
                  case .gold: return .yellow
                  case .black: return .black
                  case .white: return .white
                  }
              }
          }
      
          enum ColorScheme: String {
              case light, dark
          }
      
          enum Decoration: String, CaseIterable {
              case balloon, confetti, inflatables, noisemakers, all, none
          }
      
          private let address = "One Apple Park Way"
      
          @State private var date: Date = DateComponents(
              calendar: .current, timeZone: .current, year: 2022, month: 6, day: 6
          ).date!
          @State private var eventDescription: String =
              "Come and join us celebrate SwiftUI's birthday party!\n🎉🎂"
      
          @State private var scheme: ColorScheme = .light
          @State private var accent: Theme = .blue
          @State private var extraGuests = false
          @State private var spacesCount: Float = 2
      
          @State private var includeBalloons = false
          @State private var includeConfetti = false
          @State private var includeInflatables = false
          @State private var includeBlowers = false
      
          @State private var selectedDecorations: [Decoration] = []
          @State private var decorationThemes: [Decoration: Theme] = [
              .balloon : .blue,
              .confetti: .gold,
              .inflatables: .black,
              .noisemakers: .white,
              .none: .black
          ]
      
          private var themes: [Binding<Theme>] {
              if selectedDecorations.count == 0 {
                  return [Binding($decorationThemes[.none])!]
              }
              return selectedDecorations.compactMap {
                  Binding($decorationThemes[$0])
              }
          }
      
          var body: some View {
              Form {
                  Section {
                      LabeledContent("Location", value: address)
                      DatePicker("Date", selection: $date)
                      TextField("Description", text: $eventDescription, axis: .vertical)
                          .lineLimit(3, reservesSpace: true)
                  }
      
                  Section("Vibe") {
                      Picker("Accent color", selection: $accent) {
                          ForEach(Theme.allCases) { theme in
                              Text(theme.rawValue.capitalized).tag(theme)
                          }
                      }
                      Picker("Color scheme", selection: $scheme) {
                          Text("Light").tag(ColorScheme.light)
                          Text("Dark").tag(ColorScheme.dark)
                      }
                      #if os(macOS)
                      .pickerStyle(.inline)
                      #endif
                      Toggle(isOn: $extraGuests) {
                          Text("Allow extra guests")
                          Text("The more the merrier!")
                      }
                      if extraGuests {
                          Stepper("Guests limit", value: $spacesCount, format: .number)
                      }
                  }
      
                  Section("Decorations") {
                      Section {
                          List(selection: $selectedDecorations) {
                              DisclosureGroup {
                                  HStack {
                                      Toggle("Balloons 🎈", isOn: $includeBalloons)
                                      Spacer()
                                      decorationThemes[.balloon].map { $0.swatch }
                                  }
                                  .tag(Decoration.balloon)
      
                                  HStack {
                                      Toggle("Confetti 🎊", isOn: $includeConfetti)
                                      Spacer()
                                      decorationThemes[.confetti].map { $0.swatch }
                                  }
                                  .tag(Decoration.confetti)
      
                                  HStack {
                                      Toggle("Inflatables 🪅", isOn: $includeInflatables)
                                      Spacer()
                                      decorationThemes[.inflatables].map { $0.swatch }
                                  }
                                  .tag(Decoration.inflatables)
      
                                  HStack {
                                      Toggle("Party Horns 🥳", isOn: $includeBlowers)
                                      Spacer()
                                      decorationThemes[.noisemakers].map { $0.swatch }
                                  }
                                  .tag(Decoration.noisemakers)
                              } label: {
                                  Toggle("All Decorations", isOn: [
                                      $includeBalloons, $includeConfetti,
                                      $includeInflatables, $includeBlowers
                                  ])
                                  .tag(Decoration.all)
                              }
                              #if os(macOS)
                              .toggleStyle(.checkbox)
                              #endif
                          }
      
                          Picker("Decoration theme", selection: themes) {
                              Text("Blue").tag(Theme.blue)
                              Text("Black").tag(Theme.black)
                              Text("Gold").tag(Theme.gold)
                              Text("White").tag(Theme.white)
                          }
                          #if os(macOS)
                          .pickerStyle(.radioGroup)
                          #endif
                      }
                  }
      
              }
              .formStyle(.grouped)
          }
      }
    • 15:45 - Grouped forms with LabeledContent wrapping a view.

      struct ContentView: View {
          enum Theme: String, CaseIterable, Identifiable {
              var id: String { self.rawValue }
              case blue, gold, black, white
      
              var swatch: some View {
                  Circle()
                      .fill(color)
                      .overlay {
                          Circle().stroke(.tertiary)
                      }
                      .frame(width: 15, height: 15)
              }
      
              var color: Color {
                  switch self {
                  case .blue: return .blue
                  case .gold: return .yellow
                  case .black: return .black
                  case .white: return .white
                  }
              }
          }
      
          enum ColorScheme: String {
              case light, dark
          }
      
          enum Decoration: String, CaseIterable {
              case balloon, confetti, inflatables, noisemakers, all, none
          }
      
          private let location = Location(
              firstLine: "One Apple Park Way", secondLine: "Cupertino, CA 95014")
      
          @State private var date: Date = DateComponents(
              calendar: .current, timeZone: .current, year: 2022, month: 6, day: 6
          ).date!
          @State private var eventDescription: String =
              "Come and join us celebrate SwiftUI's birthday party!\n🎉🎂"
      
          @State private var scheme: ColorScheme = .light
          @State private var accent: Theme = .blue
          @State private var extraGuests = false
          @State private var spacesCount: Float = 2
      
          @State private var includeBalloons = false
          @State private var includeConfetti = false
          @State private var includeInflatables = false
          @State private var includeBlowers = false
      
          @State private var selectedDecorations: [Decoration] = []
          @State private var decorationThemes: [Decoration: Theme] = [
              .balloon : .blue,
              .confetti: .gold,
              .inflatables: .black,
              .noisemakers: .white,
              .none: .black
          ]
      
          private var themes: [Binding<Theme>] {
              if selectedDecorations.count == 0 {
                  return [Binding($decorationThemes[.none])!]
              }
              return selectedDecorations.compactMap {
                  Binding($decorationThemes[$0])
              }
          }
      
          var body: some View {
              Form {
                  Section {
                      LabeledContent("Location") {
                          AddressView(location)
                      }
                      DatePicker("Date", selection: $date)
                      TextField("Description", text: $eventDescription, axis: .vertical)
                          .lineLimit(3, reservesSpace: true)
                  }
      
                  Section("Vibe") {
                      Picker("Accent color", selection: $accent) {
                          ForEach(Theme.allCases) { accent in
                              Text(accent.rawValue.capitalized).tag(accent)
                          }
                      }
                      Picker("Color scheme", selection: $scheme) {
                          Text("Light").tag(ColorScheme.light)
                          Text("Dark").tag(ColorScheme.dark)
                      }
                      #if os(macOS)
                      .pickerStyle(.inline)
                      #endif
                      Toggle(isOn: $extraGuests) {
                          Text("Allow extra guests")
                          Text("The more the merrier!")
                      }
                      if extraGuests {
                          Stepper("Guests limit", value: $spacesCount, format: .number)
                      }
                  }
      
                  Section("Decorations") {
                      Section {
                          List(selection: $selectedDecorations) {
                              DisclosureGroup {
                                  HStack {
                                      Toggle("Balloons 🎈", isOn: $includeBalloons)
                                      Spacer()
                                      decorationThemes[.balloon].map { $0.swatch }
                                  }
                                  .tag(Decoration.balloon)
      
                                  HStack {
                                      Toggle("Confetti 🎊", isOn: $includeConfetti)
                                      Spacer()
                                      decorationThemes[.confetti].map { $0.swatch }
                                  }
                                  .tag(Decoration.confetti)
      
                                  HStack {
                                      Toggle("Inflatables 🪅", isOn: $includeInflatables)
                                      Spacer()
                                      decorationThemes[.inflatables].map { $0.swatch }
                                  }
                                  .tag(Decoration.inflatables)
      
                                  HStack {
                                      Toggle("Party Horns 🥳", isOn: $includeBlowers)
                                      Spacer()
                                      decorationThemes[.noisemakers].map { $0.swatch }
                                  }
                                  .tag(Decoration.noisemakers)
                              } label: {
                                  Toggle("All Decorations", isOn: [
                                      $includeBalloons, $includeConfetti,
                                      $includeInflatables, $includeBlowers
                                  ])
                                  .tag(Decoration.all)
                              }
                              #if os(macOS)
                              .toggleStyle(.checkbox)
                              #endif
                          }
      
                          Picker("Decoration theme", selection: themes) {
                              Text("Blue").tag(Theme.blue)
                              Text("Black").tag(Theme.black)
                              Text("Gold").tag(Theme.gold)
                              Text("White").tag(Theme.white)
                          }
                          #if os(macOS)
                          .pickerStyle(.radioGroup)
                          #endif
                      }
                  }
      
              }
              .formStyle(.grouped)
          }
      }
      
      
      struct AddressView: View {
          private let location: Location
      
          init(_ location: Location) {
              self.location = location
          }
      
          var body: some View {
              VStack {
                  Text(location.firstLine)
                  Text(location.secondLine)
              }
          }
      }
      
      struct Location {
          let firstLine: String
          let secondLine: String
      }
    • 17:06 - Multiline text fields

      struct ContentView: View {
          @State private var activityDates: Set<DateComponents> = [
              DateComponents(calendar: .current, year: 2022, month: 6, day: 6),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 9),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 10)
          ]
          @State private var title: String = .init()
          @State private var description: String = """
                      Join us, and let's force unwrap SwiftUl's
                      birthday presents. Note that although
                      this activity is optional, we may have
                      guards at the entry.
                      """
      
          var body: some View {
              NavigationStack {
                  Form {
                      Section {
                          TextField("Title", text: $title)
                          TextField("Description", text: $description, axis: .vertical)
                      }
                      Section("Dates") {
                          MultiDatePicker("Activities Dates", selection: $activityDates)
                      }
                  }
                  .navigationTitle("New Activity")
                  .toolbar {
                      Button("Save") {}
                  }
              }
          }
      }
    • 17:20 - Multiline text fields with line limit

      struct ContentView: View {
          @State private var activityDates: Set<DateComponents> = [
              DateComponents(calendar: .current, year: 2022, month: 6, day: 6),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 9),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 10)
          ]
          @State private var title: String = .init()
          @State private var description: String = """
                      Join us, and let's force unwrap SwiftUl's
                      birthday presents. Note that although
                      this activity is optional, we may have
                      guards at the entry.
                      """
      
          var body: some View {
              NavigationStack {
                  Form {
                      Section {
                          TextField("Title", text: $title)
                          TextField("Description", text: $description, axis: .vertical)
                        		.lineLimit(5)
                      }
                      Section("Dates") {
                          MultiDatePicker("Activities Dates", selection: $activityDates)
                      }
                  }
                  .navigationTitle("New Activity")
                  .toolbar {
                      Button("Save") {}
                  }
              }
          }
      }
    • 17:23 - Multiline text fields with line limit range

      struct ContentView: View {
          @State private var activityDates: Set<DateComponents> = [
              DateComponents(calendar: .current, year: 2022, month: 6, day: 6),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 9),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 10)
          ]
          @State private var title: String = .init()
          @State private var description: String = """
                      Join us, and let's force unwrap SwiftUl's
                      birthday presents. Note that although
                      this activity is optional, we may have
                      guards at the entry.
                      """
      
          var body: some View {
              NavigationStack {
                  Form {
                      Section {
                          TextField("Title", text: $title)
                          TextField("Description", text: $description, axis: .vertical)
                        		.lineLimit(5...10)
                      }
                      Section("Dates") {
                          MultiDatePicker("Activities Dates", selection: $activityDates)
                      }
                  }
                  .navigationTitle("New Activity")
                  .toolbar {
                      Button("Save") {}
                  }
              }
          }
      }
    • 17:40 - MultiDatePicker

      struct ContentView: View {
          @State private var activityDates: Set<DateComponents> = [
              DateComponents(calendar: .current, year: 2022, month: 6, day: 6),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 9),
              DateComponents(calendar: .current, year: 2022, month: 6, day: 10)
          ]
          @State private var title: String = .init()
          @State private var description: String = """
                      Join us, and let's force unwrap SwiftUl's
                      birthday presents. Note that although
                      this activity is optional, we may have
                      guards at the entry.
                      """
      
          var body: some View {
              NavigationStack {
                  Form {
                      Section {
                          TextField("Title", text: $title)
                          TextField("Description", text: $description, axis: .vertical)
                      }
                      Section("Dates") {
                          MultiDatePicker("Activities Dates", selection: $activityDates)
                      }
                  }
                  .navigationTitle("New Activity")
                  .toolbar {
                      Button("Save") {}
                  }
              }
          }
      }
    • 18:10 - Mixed-state toggles & pickers

      struct ContentView: View {
          enum Theme: String, CaseIterable, Identifiable {
              var id: String { self.rawValue }
              case blue, gold, black, white
      
              var swatch: some View {
                  Circle()
                      .fill(color)
                      .overlay {
                          Circle().stroke(.tertiary)
                      }
                      .frame(width: 15, height: 15)
              }
      
              var color: Color {
                  switch self {
                  case .blue: return .blue
                  case .gold: return .yellow
                  case .black: return .black
                  case .white: return .white
                  }
              }
          }
      
          enum ColorScheme: String {
              case light, dark
          }
      
          enum Decoration: String, CaseIterable {
              case balloon, confetti, inflatables, noisemakers, all, none
          }
      
          private let location = Location(
              firstLine: "One Apple Park Way", secondLine: "Cupertino, CA 95014")
      
          @State private var date: Date = DateComponents(
              calendar: .current, timeZone: .current, year: 2022, month: 6, day: 6
          ).date!
          @State private var eventDescription: String =
              "Come and join us celebrate SwiftUI's birthday party!\n🎉🎂"
      
          @State private var scheme: ColorScheme = .light
          @State private var accent: Theme = .blue
          @State private var extraGuests = false
          @State private var spacesCount: Float = 2
      
          @State private var includeBalloons = false
          @State private var includeConfetti = false
          @State private var includeInflatables = false
          @State private var includeBlowers = false
      
          @State private var selectedDecorations: [Decoration] = []
          @State private var decorationThemes: [Decoration: Theme] = [
              .balloon : .blue,
              .confetti: .gold,
              .inflatables: .black,
              .noisemakers: .white,
              .none: .black
          ]
      
          private var themes: [Binding<Theme>] {
              if selectedDecorations.count == 0 {
                  return [Binding($decorationThemes[.none])!]
              }
              return selectedDecorations.compactMap {
                  Binding($decorationThemes[$0])
              }
          }
      
          var body: some View {
              Form {
                  Section {
                      LabeledContent("Location") {
                          AddressView(location)
                      }
                      DatePicker("Date", selection: $date)
                      TextField("Description", text: $eventDescription, axis: .vertical)
                          .lineLimit(3, reservesSpace: true)
                  }
      
                  Section("Vibe") {
                      Picker("Accent color", selection: $accent) {
                          ForEach(Theme.allCases) { accent in
                              Text(accent.rawValue.capitalized).tag(accent)
                          }
                      }
                      Picker("Color scheme", selection: $scheme) {
                          Text("Light").tag(ColorScheme.light)
                          Text("Dark").tag(ColorScheme.dark)
                      }
                      #if os(macOS)
                      .pickerStyle(.inline)
                      #endif
                      Toggle(isOn: $extraGuests) {
                          Text("Allow extra guests")
                          Text("The more the merrier!")
                      }
                      if extraGuests {
                          Stepper("Guests limit", value: $spacesCount, format: .number)
                      }
                  }
      
                  Section("Decorations") {
                      Section {
                          List(selection: $selectedDecorations) {
                              DisclosureGroup {
                                  HStack {
                                      Toggle("Balloons 🎈", isOn: $includeBalloons)
                                      Spacer()
                                      decorationThemes[.balloon].map { $0.swatch }
                                  }
                                  .tag(Decoration.balloon)
      
                                  HStack {
                                      Toggle("Confetti 🎊", isOn: $includeConfetti)
                                      Spacer()
                                      decorationThemes[.confetti].map { $0.swatch }
                                  }
                                  .tag(Decoration.confetti)
      
                                  HStack {
                                      Toggle("Inflatables 🪅", isOn: $includeInflatables)
                                      Spacer()
                                      decorationThemes[.inflatables].map { $0.swatch }
                                  }
                                  .tag(Decoration.inflatables)
      
                                  HStack {
                                      Toggle("Party Horns 🥳", isOn: $includeBlowers)
                                      Spacer()
                                      decorationThemes[.noisemakers].map { $0.swatch }
                                  }
                                  .tag(Decoration.noisemakers)
                              } label: {
                                  Toggle("All Decorations", isOn: [
                                      $includeBalloons, $includeConfetti,
                                      $includeInflatables, $includeBlowers
                                  ])
                                  .tag(Decoration.all)
                              }
                              #if os(macOS)
                              .toggleStyle(.checkbox)
                              #endif
                          }
      
                          Picker("Decoration theme", selection: themes) {
                              Text("Blue").tag(Theme.blue)
                              Text("Black").tag(Theme.black)
                              Text("Gold").tag(Theme.gold)
                              Text("White").tag(Theme.white)
                          }
                          #if os(macOS)
                          .pickerStyle(.radioGroup)
                          #endif
                      }
                  }
      
              }
              .formStyle(.grouped)
          }
      }
      
      
      struct AddressView: View {
          private let location: Location
      
          init(_ location: Location) {
              self.location = location
          }
      
          var body: some View {
              VStack {
                  Text(location.firstLine)
                  Text(location.secondLine)
              }
          }
      }
      
      struct Location {
          let firstLine: String
          let secondLine: String
      }
    • 18:53 - ButtonStyle composition & Steppers

      struct ContentView: View {
          enum Theme: String, CaseIterable, Identifiable {
              var id: String { self.rawValue }
              case blue, gold, black, white
      
              var swatch: some View {
                  Circle()
                      .fill(color)
                      .overlay {
                          Circle().stroke(.tertiary)
                      }
                      .frame(width: 15, height: 15)
              }
      
              var color: Color {
                  switch self {
                  case .blue: return .blue
                  case .gold: return .yellow
                  case .black: return .black
                  case .white: return .white
                  }
              }
          }
      
          enum ColorScheme: String {
              case light, dark
          }
      
          enum Decoration: String, CaseIterable {
              case balloon, confetti, inflatables, noisemakers, all, none
          }
      
          private let location = Location(
              firstLine: "One Apple Park Way", secondLine: "Cupertino, CA 95014")
      
          @State private var date: Date = DateComponents(
              calendar: .current, timeZone: .current, year: 2022, month: 6, day: 6
          ).date!
          @State private var eventDescription: String =
              "Come and join us celebrate SwiftUI's birthday party!\n🎉🎂"
      
          @State private var scheme: ColorScheme = .light
          @State private var accent: Theme = .blue
          @State private var extraGuests = false
          @State private var spacesCount: Float = 2
      
          @State private var includeBalloons = false
          @State private var includeConfetti = false
          @State private var includeInflatables = false
          @State private var includeBlowers = false
      
          @State private var swiftastic = false
          @State private var wwdcParty = true
          @State private var offTheCharts = true
          @State private var oneMoreThing = false
      
          @State private var selectedDecorations: [Decoration] = []
          @State private var decorationThemes: [Decoration: Theme] = [
              .balloon : .blue,
              .confetti: .gold,
              .inflatables: .black,
              .noisemakers: .white,
              .none: .black
          ]
      
          private var themes: [Binding<Theme>] {
              if selectedDecorations.count == 0 {
                  return [Binding($decorationThemes[.none])!]
              }
              return selectedDecorations.compactMap {
                  Binding($decorationThemes[$0])
              }
          }
      
          var body: some View {
              Form {
                  Section {
                      LabeledContent("Location") {
                          AddressView(location)
                      }
                      DatePicker("Date", selection: $date)
                      TextField("Description", text: $eventDescription, axis: .vertical)
                          .lineLimit(3, reservesSpace: true)
                  }
      
                  Section("Vibe") {
                      Picker("Accent color", selection: $accent) {
                          ForEach(Theme.allCases) { accent in
                              Text(accent.rawValue.capitalized).tag(accent)
                          }
                      }
                      Picker("Color scheme", selection: $scheme) {
                          Text("Light").tag(ColorScheme.light)
                          Text("Dark").tag(ColorScheme.dark)
                      }
                      #if os(macOS)
                      .pickerStyle(.inline)
                      #endif
                      Toggle(isOn: $extraGuests) {
                          Text("Allow extra guests")
                          Text("The more the merrier!")
                      }
                      if extraGuests {
                          Stepper("Guests limit", value: $spacesCount, format: .number)
                      }
                  }
      
                  Section("Decorations") {
                      Section {
                          List {
                              DisclosureGroup {
                                  HStack {
                                      Toggle("Balloons 🎈", isOn: $includeBalloons)
                                      Spacer()
                                      decorationThemes[.balloon].map { $0.swatch }
                                  }
                                  .tag(Decoration.balloon)
      
                                  HStack {
                                      Toggle("Confetti 🎊", isOn: $includeConfetti)
                                      Spacer()
                                      decorationThemes[.confetti].map { $0.swatch }
                                  }
                                  .tag(Decoration.confetti)
      
                                  HStack {
                                      Toggle("Inflatables 🪅", isOn: $includeInflatables)
                                      Spacer()
                                      decorationThemes[.inflatables].map { $0.swatch }
                                  }
                                  .tag(Decoration.inflatables)
      
                                  HStack {
                                      Toggle("Party Horns 🥳", isOn: $includeBlowers)
                                      Spacer()
                                      decorationThemes[.noisemakers].map { $0.swatch }
                                  }
                                  .tag(Decoration.noisemakers)
                              } label: {
                                  Toggle("All Decorations", isOn: [
                                      $includeBalloons, $includeConfetti,
                                      $includeInflatables, $includeBlowers
                                  ])
                                  .tag(Decoration.all)
                              }
                              #if os(macOS)
                              .toggleStyle(.checkbox)
                              #endif
                          }
      
                          Picker("Decoration theme", selection: themes) {
                              Text("Blue").tag(Theme.blue)
                              Text("Black").tag(Theme.black)
                              Text("Gold").tag(Theme.gold)
                              Text("White").tag(Theme.white)
                          }
                          #if os(macOS)
                          .pickerStyle(.radioGroup)
                          #endif
                      }
                  }
      
                  Section("Hashtags") {
                      VStack(alignment: .leading) {
                          HStack {
                              Toggle("#Swiftastic", isOn: $swiftastic)
                              Toggle("#WWParty", isOn: $wwdcParty)
                          }
                          HStack {
                              Toggle("#OffTheCharts", isOn: $offTheCharts)
                              Toggle("#OneMoreThing", isOn: $oneMoreThing)
                          }
                      }
                      .toggleStyle(.button)
                      .buttonStyle(.bordered)
                  }
      
              }
              .formStyle(.grouped)
          }
      }
      
      struct AddressView: View {
          private let location: Location
      
          init(_ location: Location) {
              self.location = location
          }
      
          var body: some View {
              VStack {
                  Text(location.firstLine)
                  Text(location.secondLine)
              }
          }
      }
      
      struct Location {
          let firstLine: String
          let secondLine: String
      }
    • 19:33 - Accessibility Quick Actions

      struct ContentView: View {
          @State private var isInCart: Bool = false
      
          var body: some View {
              VStack(alignment: .leading) {
                  ItemDescriptionView()
                  addToCartButton
              }
              .accessibilityQuickAction(style: .prompt) {
                  addToCartButton
              }
          }
      
          var addToCartButton: some View {
              Button(isInCart ? "Remove from cart" : "Add to cart") {
                  isInCart.toggle()
              }
          }
      }
      
      struct ItemDescriptionView: View {
          var body: some View {
              ScrollView {
                  VStack {
                      HStack {
                          Text("🎈")
                              .font(.title2)
                          Text("Balloons")
                              .font(.title3)
                          Spacer()
                      }
                      .padding(.bottom, 4)
                      Text(
                          """
                          This is perhaps our funniest product! It is made up of a
                          rubber fabric and comes in various unique colors.
                          """)
                      .font(.caption)
                  }
              }
          }
      }
    • 20:20 - Tables on iPadOS

      struct ContentView: View {
          @StateObject private var attendeeStore = AttendeeStore()
          var body: some View {
              NavigationStack {
                  Table(attendeeStore.attendees) {
                      TableColumn("Name") { attendee in
                          AttendeeRow(attendee)
                      }
                      TableColumn("City", value: \.city)
                      TableColumn("Status") { attendee in
                          StatusRow(attendee)
                      }
                  }
                  .navigationTitle("Invitations")
                  .toolbar(id: "toolbar") {
                      ToolbarItem(id: "new", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("New Invitation", systemImage: "envelope")
                          }
                      }
                      ToolbarItem(id: "edit", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Edit", systemImage: "pencil.circle")
                          }
                      }
                      ToolbarItem(id: "share", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Share", systemImage: "square.and.arrow.up")
                          }
                      }
                      ToolbarItem(id: "tag", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Tags", systemImage: "tag")
                          }
                      }
                      ToolbarItem(
                          id: "reminder", placement: .secondaryAction, showsByDefault: false
                      ) {
                          Button(action: {}) {
                              Label("Set reminder", systemImage: "bell")
                          }
                      }
                  }
                  .toolbarRole(.editor)
              }
          }
      }
      
      class AttendeeStore: ObservableObject {
          @Published var attendees: [Attendee] = [/* Default attendees */]
      }
      
      
      struct Attendee: Identifiable, Hashable {
          enum Status: String {
              case accepted, declined, maybe
      
              func displayText() -> Text {
                  switch self {
                  case .accepted: return Text(
                      "Accepted \(Image(systemName: "person.crop.circle.badge.checkmark"))")
                  case .maybe: return Text(
                      "Maybe \(Image(systemName: "person.crop.circle.badge.questionmark"))")
                  case .declined: return Text(
                      "Declined \(Image(systemName: "person.crop.circle.badge.minus"))")
                  }
              }
          }
          
          let id = UUID()
          let memojiName: String
          let name: String
          let city: String
          let status: Status
      
          init(memojiName: String, name: String, cities: String, status: Status) {
              self.memojiName = memojiName
              self.name = name
              self.city = cities
              self.status = status
          }
      }
      
      struct AttendeeRow: View {
          let attendee: Attendee
      
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              HStack {
                  Image(attendee.memojiName)
                      .resizable()
                      .aspectRatio(contentMode: .fill)
                      #if os(macOS)
                      .frame(width: 20, height: 20)
                      .overlay {
                          Circle()
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #else
                      .frame(width: 32, height: 32)
                      .overlay {
                          RoundedRectangle(cornerRadius: 6)
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #endif
                  Text(attendee.name)
              }
          }
      }
      
      struct StatusRow: View {
          let attendee: Attendee
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              attendee.status.displayText()
                  .symbolVariant(.fill)
                  .symbolRenderingMode(.multicolor)
          }
      }
    • 21:12 - Context Menu

      struct ContentView: View {
          @StateObject private var attendeeStore = AttendeeStore()
          @State private var selection = Set<Attendee.ID>()
      
          var body: some View {
              NavigationStack {
                  Table(attendeeStore.attendees, selection: $selection) {
                      TableColumn("Name") { attendee in
                          AttendeeRow(attendee)
                      }
                      TableColumn("City", value: \.city)
                      TableColumn("Status") { attendee in
                          StatusRow(attendee)
                      }
                  }
                  .navigationTitle("Invitations")
                  #if os(macOS)
                  .contextMenu(forSelectionType: Attendee.ID.self) { selection in
                      if selection.isEmpty {
                          Button("New Invitation") { addInvitation() }
                      } else if selection.count == 1 {
                          Button("Mark as VIP") { markVIPs(selection) }
                      } else {
                          Button("Mark as VIPs") { markVIPs(selection) }
                      }
                  }
                  #endif
                  .toolbar(id: "toolbar") {
                      ToolbarItem(id: "new", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("New Invitation", systemImage: "envelope")
                          }
                      }
                      ToolbarItem(id: "edit", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Edit", systemImage: "pencil.circle")
                          }
                      }
                      ToolbarItem(id: "share", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Share", systemImage: "square.and.arrow.up")
                          }
                      }
                      ToolbarItem(id: "tag", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Tags", systemImage: "tag")
                          }
                      }
                      ToolbarItem(
                          id: "reminder", placement: .secondaryAction, showsByDefault: false
                      ) {
                          Button(action: {}) {
                              Label("Set reminder", systemImage: "bell")
                          }
                      }
                  }
                  .toolbarRole(.editor)
              }
          }
      
          private func addInvitation() {}
      
          private func markVIPs(_ items: Set<String>) {}
      }
      
      
      class AttendeeStore: ObservableObject {
          @Published var attendees: [Attendee] = [/* Default attendees */]
      }
      
      
      struct Attendee: Identifiable, Hashable {
          enum Status: String {
              case accepted, declined, maybe
      
              func displayText() -> Text {
                  switch self {
                  case .accepted: return Text(
                      "Accepted \(Image(systemName: "person.crop.circle.badge.checkmark"))")
                  case .maybe: return Text(
                      "Maybe \(Image(systemName: "person.crop.circle.badge.questionmark"))")
                  case .declined: return Text(
                      "Declined \(Image(systemName: "person.crop.circle.badge.minus"))")
                  }
              }
          }
      
          let id = UUID()
          let memojiName: String
          let name: String
          let city: String
          let status: Status
      
          init(memojiName: String, name: String, cities: String, status: Status) {
              self.memojiName = memojiName
              self.name = name
              self.city = cities
              self.status = status
          }
      }
      
      struct AttendeeRow: View {
          let attendee: Attendee
      
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              HStack {
                  Image(attendee.memojiName)
                      .resizable()
                      .aspectRatio(contentMode: .fill)
                      #if os(macOS)
                      .frame(width: 20, height: 20)
                      .overlay {
                          Circle()
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #else
                      .frame(width: 32, height: 32)
                      .overlay {
                          RoundedRectangle(cornerRadius: 6)
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #endif
                  Text(attendee.name)
              }
          }
      }
      
      struct StatusRow: View {
          let attendee: Attendee
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              attendee.status.displayText()
                  .symbolVariant(.fill)
                  .symbolRenderingMode(.multicolor)
          }
      }
    • 22:12 - Customizable toolbars

      struct ContentView: View {
          @StateObject private var attendeeStore = AttendeeStore()
          @State private var selection = Set<Attendee.ID>()
      
          var body: some View {
              NavigationStack {
                  Table(attendeeStore.attendees, selection: $selection) {
                      TableColumn("Name") { attendee in
                          AttendeeRow(attendee)
                      }
                      TableColumn("City", value: \.city)
                      TableColumn("Status") { attendee in
                          StatusRow(attendee)
                      }
                  }
                  .navigationTitle("Invitations")
                  #if os(macOS)
                  .contextMenu(forSelectionType: Attendee.ID.self) { selection in
                      if selection.isEmpty {
                          Button("New Invitation") { addInvitation() }
                      } else if selection.count == 1 {
                          Button("Mark as VIP") { markVIPs(selection) }
                      } else {
                          Button("Mark as VIPs") { markVIPs(selection) }
                      }
                  }
                  #endif
                  .toolbar(id: "toolbar") {
                      ToolbarItem(id: "new", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("New Invitation", systemImage: "envelope")
                          }
                      }
                      ToolbarItem(id: "edit", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Edit", systemImage: "pencil.circle")
                          }
                      }
                      ToolbarItem(id: "share", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Share", systemImage: "square.and.arrow.up")
                          }
                      }
                      ToolbarItem(id: "tag", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Tags", systemImage: "tag")
                          }
                      }
                      ToolbarItem(
                          id: "reminder", placement: .secondaryAction, showsByDefault: false
                      ) {
                          Button(action: {}) {
                              Label("Set reminder", systemImage: "bell")
                          }
                      }
                  }
                  .toolbarRole(.editor)
              }
          }
      
          private func addInvitation() {}
      
          private func markVIPs(_ items: Set<String>) {}
      }
      
      
      class AttendeeStore: ObservableObject {
          @Published var attendees: [Attendee] = [/* Default attendees */]
      }
      
      
      struct Attendee: Identifiable, Hashable {
          enum Status: String {
              case accepted, declined, maybe
      
              func displayText() -> Text {
                  switch self {
                  case .accepted: return Text(
                      "Accepted \(Image(systemName: "person.crop.circle.badge.checkmark"))")
                  case .maybe: return Text(
                      "Maybe \(Image(systemName: "person.crop.circle.badge.questionmark"))")
                  case .declined: return Text(
                      "Declined \(Image(systemName: "person.crop.circle.badge.minus"))")
                  }
              }
          }
      
          let id = UUID()
          let memojiName: String
          let name: String
          let city: String
          let status: Status
      
          init(memojiName: String, name: String, cities: String, status: Status) {
              self.memojiName = memojiName
              self.name = name
              self.city = cities
              self.status = status
          }
      }
      
      struct AttendeeRow: View {
          let attendee: Attendee
      
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              HStack {
                  Image(attendee.memojiName)
                      .resizable()
                      .aspectRatio(contentMode: .fill)
                      #if os(macOS)
                      .frame(width: 20, height: 20)
                      .overlay {
                          Circle()
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #else
                      .frame(width: 32, height: 32)
                      .overlay {
                          RoundedRectangle(cornerRadius: 6)
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #endif
                  Text(attendee.name)
              }
          }
      }
      
      struct StatusRow: View {
          let attendee: Attendee
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              attendee.status.displayText()
                  .symbolVariant(.fill)
                  .symbolRenderingMode(.multicolor)
          }
      }
    • 23:17 - Search Tokens

      struct ContentView: View {
          public struct AttendeeToken: Identifiable, Equatable, Hashable {
              enum Guts {
                  case name
                  case location
                  case status
              }
      
              let guts: Guts
              var query: String = .init()
      
              var id: String {
                  self.systemImage
              }
      
              static let allCases: [AttendeeToken] = [.name, .location, .status]
      
              mutating func displayName(_ query: String) -> String {
                  self.query = query
                  switch guts {
                  case .name: return "Name contains: \(query)"
                  case .location: return "City contains: \(query)"
                  case .status: return "Status contains: \(query)"
                  }
              }
      
              var systemImage: String {
                  switch guts {
                  case .name: return "person"
                  case .location: return "location.square"
                  case .status: return "person.crop.circle.badge"
                  }
              }
      
              static let name: AttendeeToken = .init(guts: .name)
              static let location: AttendeeToken = .init(guts: .location)
              static let status: AttendeeToken = .init(guts: .status)
          }
      
          @StateObject private var attendeeStore = AttendeeStore()
          @State private var selection = Set<Attendee.ID>()
      
          @State private var tokens: [AttendeeToken] = .init()
          @State private var query: String = .init()
      
          var body: some View {
              NavigationStack {
                  Table(attendeeStore.attendees, selection: $selection) {
                      TableColumn("Name") { attendee in
                          AttendeeRow(attendee)
                      }
                      TableColumn("City", value: \.city)
                      TableColumn("Status") { attendee in
                          StatusRow(attendee)
                      }
                  }
                  .navigationTitle("Invitations")
                  #if os(macOS)
                  .contextMenu(forSelectionType: Attendee.ID.self) { selection in
                      if selection.isEmpty {
                          Button("New Invitation") { addInvitation() }
                      } else if selection.count == 1 {
                          Button("Mark as VIP") { markVIPs(selection) }
                      } else {
                          Button("Mark as VIPs") { markVIPs(selection) }
                      }
                  }
                  #endif
                  .searchable(text: $query, tokens: $tokens) { token in
                      Label(token.query, systemImage: token.systemImage)
                  } suggestions: {
                      suggestions
                  }
                  .toolbar(id: "toolbar") {
                      ToolbarItem(id: "new", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("New Invitation", systemImage: "envelope")
                          }
                      }
                      ToolbarItem(id: "edit", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Edit", systemImage: "pencil.circle")
                          }
                      }
                      ToolbarItem(id: "share", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Share", systemImage: "square.and.arrow.up")
                          }
                      }
                      ToolbarItem(id: "tag", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Tags", systemImage: "tag")
                          }
                      }
                      ToolbarItem(
                          id: "reminder", placement: .secondaryAction, showsByDefault: false
                      ) {
                          Button(action: {}) {
                              Label("Set reminder", systemImage: "bell")
                          }
                      }
                  }
                  .toolbarRole(.editor)
              }
          }
      
          @ViewBuilder
          private var suggestions: some View {
              ForEach(attendeeStore.attendees) {
                  Text($0.name)
                      .foregroundColor(.black)
              }
      
              if !query.isEmpty {
                  ForEach(AttendeeToken.allCases) { token in
                      var _token = token
                      Label(_token.displayName(query), systemImage: _token.systemImage)
                          .searchCompletion(_token)
                  }
              }
          }
      
          private func addInvitation() {}
      
          private func markVIPs(_ items: Set<String>) {}
      }
      
      class AttendeeStore: ObservableObject {
          @Published var attendees: [Attendee] = [/* Default attendees */]
      }
      
      struct Attendee: Identifiable, Hashable {
          enum Status: String {
              case accepted, declined, maybe
      
              func displayText() -> Text {
                  switch self {
                  case .accepted: return Text(
                      "Accepted \(Image(systemName: "person.crop.circle.badge.checkmark"))")
                  case .maybe: return Text(
                      "Maybe \(Image(systemName: "person.crop.circle.badge.questionmark"))")
                  case .declined: return Text(
                      "Declined \(Image(systemName: "person.crop.circle.badge.minus"))")
                  }
              }
          }
      
          let id = UUID()
          let memojiName: String
          let name: String
          let city: String
          let status: Status
      
          init(memojiName: String, name: String, cities: String, status: Status) {
              self.memojiName = memojiName
              self.name = name
              self.city = cities
              self.status = status
          }
      }
      
      struct AttendeeRow: View {
          let attendee: Attendee
      
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              HStack {
                  Image(attendee.memojiName)
                      .resizable()
                      .aspectRatio(contentMode: .fill)
                      #if os(macOS)
                      .frame(width: 20, height: 20)
                      .overlay {
                          Circle()
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #else
                      .frame(width: 32, height: 32)
                      .overlay {
                          RoundedRectangle(cornerRadius: 6)
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #endif
                  Text(attendee.name)
              }
          }
      }
      
      struct StatusRow: View {
          let attendee: Attendee
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              attendee.status.displayText()
                  .symbolVariant(.fill)
                  .symbolRenderingMode(.multicolor)
          }
      }
    • 23:28 - Search scopes

      struct ContentView: View {
          enum AttendanceScope {
              case inPerson
              case online
          }
      
          public struct AttendeeToken: Identifiable, Equatable, Hashable {
              enum Guts {
                  case name
                  case location
                  case status
              }
      
              let guts: Guts
              var query: String = .init()
      
              var id: String {
                  self.systemImage
              }
      
              static let allCases: [AttendeeToken] = [.name, .location, .status]
      
              mutating func displayName(_ query: String) -> String {
                  self.query = query
                  switch guts {
                  case .name: return "Name contains: \(query)"
                  case .location: return "City contains: \(query)"
                  case .status: return "Status contains: \(query)"
                  }
              }
      
              var systemImage: String {
                  switch guts {
                  case .name: return "person"
                  case .location: return "location.square"
                  case .status: return "person.crop.circle.badge"
                  }
              }
      
              static let name: AttendeeToken = .init(guts: .name)
              static let location: AttendeeToken = .init(guts: .location)
              static let status: AttendeeToken = .init(guts: .status)
          }
      
          @StateObject private var attendeeStore = AttendeeStore()
          @State private var selection = Set<Attendee.ID>()
      
          @State private var tokens: [AttendeeToken] = .init()
          @State private var query: String = .init()
          @State private var scope: AttendanceScope = .inPerson
      
          var body: some View {
              NavigationStack {
                  Table(attendeeStore.attendees, selection: $selection) {
                      TableColumn("Name") { attendee in
                          AttendeeRow(attendee)
                      }
                      TableColumn("City", value: \.city)
                      TableColumn("Status") { attendee in
                          StatusRow(attendee)
                      }
                  }
                  .navigationTitle("Invitations")
                  #if os(macOS)
                  .contextMenu(forSelectionType: Attendee.ID.self) { selection in
                      if selection.isEmpty {
                          Button("New Invitation") { addInvitation() }
                      } else if selection.count == 1 {
                          Button("Mark as VIP") { markVIPs(selection) }
                      } else {
                          Button("Mark as VIPs") { markVIPs(selection) }
                      }
                  }
                  #endif
                  .searchable(
                      text: $query, tokens: $tokens, scope: $scope
                  ) { token in
                      Label(
                          token.query,
                          systemImage: token.systemImage)
                  } scopes: {
                      Text("In Person").tag(AttendanceScope.inPerson)
                      Text("Online").tag(AttendanceScope.online)
                  } suggestions: {
                      suggestions
                  }
                  .toolbar(id: "toolbar") {
                      ToolbarItem(id: "new", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("New Invitation", systemImage: "envelope")
                          }
                      }
                      ToolbarItem(id: "edit", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Edit", systemImage: "pencil.circle")
                          }
                      }
                      ToolbarItem(id: "share", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Share", systemImage: "square.and.arrow.up")
                          }
                      }
                      ToolbarItem(id: "tag", placement: .secondaryAction) {
                          Button(action: {}) {
                              Label("Tags", systemImage: "tag")
                          }
                      }
                      ToolbarItem(
                          id: "reminder", placement: .secondaryAction, showsByDefault: false
                      ) {
                          Button(action: {}) {
                              Label("Set reminder", systemImage: "bell")
                          }
                      }
                  }
                  .toolbarRole(.editor)
              }
          }
      
          @ViewBuilder
          private var suggestions: some View {
              ForEach(attendeeStore.attendees) {
                  Text($0.name)
                      .foregroundColor(.black)
              }
      
              if !query.isEmpty {
                  ForEach(AttendeeToken.allCases) { token in
                      var _token = token
                      Label(_token.displayName(query), systemImage: _token.systemImage)
                          .searchCompletion(_token)
                  }
              }
          }
      
          private func addInvitation() {}
      
          private func markVIPs(_ items: Set<String>) {}
      }
      
      class AttendeeStore: ObservableObject {
          @Published var attendees: [Attendee] = [/* Default attendees */]
      }
      
      
      struct Attendee: Identifiable, Hashable {
          enum Status: String {
              case accepted, declined, maybe
      
              func displayText() -> Text {
                  switch self {
                  case .accepted: return Text(
                      "Accepted \(Image(systemName: "person.crop.circle.badge.checkmark"))")
                  case .maybe: return Text(
                      "Maybe \(Image(systemName: "person.crop.circle.badge.questionmark"))")
                  case .declined: return Text(
                      "Declined \(Image(systemName: "person.crop.circle.badge.minus"))")
                  }
              }
          }
      
          let id = UUID()
          let memojiName: String
          let name: String
          let city: String
          let status: Status
      
          init(memojiName: String, name: String, cities: String, status: Status) {
              self.memojiName = memojiName
              self.name = name
              self.city = cities
              self.status = status
          }
      }
      
      struct AttendeeRow: View {
          let attendee: Attendee
      
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              HStack {
                  Image(attendee.memojiName)
                      .resizable()
                      .aspectRatio(contentMode: .fill)
                      #if os(macOS)
                      .frame(width: 20, height: 20)
                      .overlay {
                          Circle()
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #else
                      .frame(width: 32, height: 32)
                      .overlay {
                          RoundedRectangle(cornerRadius: 6)
                              .stroke(Color.gray.opacity(0.2), lineWidth: 1)
                      }
                      #endif
                  Text(attendee.name)
              }
          }
      }
      
      struct StatusRow: View {
          let attendee: Attendee
          init(_ attendee: Attendee) {
              self.attendee = attendee
          }
      
          var body: some View {
              attendee.status.displayText()
                  .symbolVariant(.fill)
                  .symbolRenderingMode(.multicolor)
          }
      }
    • 24:45 - PhotosPicker

      import PhotosUI
      import CoreTransferable
      
      struct ContentView: View {
          @ObservedObject var viewModel: FilterModel = .shared
          
          var body: some View {
              NavigationStack {
                  Gallery()
                      .navigationTitle("Birthday Filter")
                      .toolbar {
                          PhotosPicker(
                              selection: $viewModel.imageSelection,
                              matching: .images
                          ) {
                              Label("Pick a photo", systemImage: "plus.app")
                          }
                          Button {
                              viewModel.applyFilter()
                          } label: {
                              Label("Apply Filter", systemImage: "camera.filters")
                          }
                      }
              }
          }
      }
      
      struct Gallery: View {
          @ObservedObject var viewModel: FilterModel = .shared
      
          var body: some View {
              VStack {
                  switch viewModel.imageState {
                  case .success(let image):
                      image
                          .resizable()
                          .aspectRatio(contentMode: .fill)
                          .draggable(image)
                  case .loading:
                      ProgressView()
                  case .empty:
                      Text("No Photo \(Image(systemName: "photo"))")
                          .font(.title2)
                          .fontWeight(.semibold)
                      Text("Drag and drop a photo or press\n \(Image(systemName: "plus.app")) to choose a photo manually.")
                          .foregroundColor(.secondary)
                          .multilineTextAlignment(.center)
                  case .failure:
                      Image(systemName: "exclamationmark.triangle.fill")
                          .font(.system(size: 40))
                          .foregroundColor(.white)
                  }
              }
              .padding()
          }
      }
      
      @MainActor
      class FilterModel: ObservableObject {
          static let shared = FilterModel()
      
          enum ImageState {
              case empty, loading(Progress), success(Image), failure(Error)
          }
      
          @Published private(set) var processedImage: Image?
          @Published var imageState: ImageState = .empty
          @Published var imageSelection: PhotosPickerItem? = nil {
              didSet {
                  if let imageSelection = imageSelection {
                      let progress = loadTransferable(from: imageSelection)
                      imageState = .loading(progress)
                  } else {
                      imageState = .empty
                  }
              }
          }
      
          func applyFilter() { /* Apply your filter */ }
      
          private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
              return imageSelection.loadTransferable(type: Image.self) { result in
                  DispatchQueue.main.async {
                      guard imageSelection == self.imageSelection else { return }
                      switch result {
                      case .success(let image?):
                          self.imageState = .success(image)
                      case .success(nil):
                          self.imageState = .empty
                      case .failure(let error):
                          self.imageState = .failure(error)
                      }
                  }
              }
          }
      }
    • 25:51 - ShareLink

      import PhotosUI
      import CoreTransferable
      
      struct ContentView: View {
          @ObservedObject var viewModel: FilterModel = .shared
      
          var body: some View {
              NavigationStack {
                  Gallery()
                      .navigationTitle("Birthday Filter")
                      .toolbar {
                          PhotosPicker(
                              selection: $viewModel.imageSelection,
                              matching: .images
                          ) {
                              Label("Pick a photo", systemImage: "plus.app")
                          }
                          Button {
                              viewModel.applyFilter()
                          } label: {
                              Label("Apply Filter", systemImage: "camera.filters")
                          }
                          if let item = viewModel.processedImage {
                              ShareLink(
                                  item: item, preview: SharePreview("Birthday Effects"))
                          }
                      }
              }
          }
      }
      
      struct Gallery: View {
          @ObservedObject var viewModel: FilterModel = .shared
      
          var body: some View {
              VStack {
                  switch viewModel.imageState {
                  case .success(let image):
                      image
                          .resizable()
                          .aspectRatio(contentMode: .fill)
                          .draggable(image)
                  case .loading:
                      ProgressView()
                  case .empty:
                      Text("No Photo \(Image(systemName: "photo"))")
                          .font(.title2)
                          .fontWeight(.semibold)
                      Text("Drag and drop a photo or press\n \(Image(systemName: "plus.app")) to choose a photo manually.")
                          .foregroundColor(.secondary)
                          .multilineTextAlignment(.center)
                  case .failure:
                      Image(systemName: "exclamationmark.triangle.fill")
                          .font(.system(size: 40))
                          .foregroundColor(.white)
                  }
              }
              .padding()
          }
      }
      
      @MainActor
      class FilterModel: ObservableObject {
          static let shared = FilterModel()
      
          enum ImageState {
              case empty, loading(Progress), success(Image), failure(Error)
          }
      
          @Published private(set) var processedImage: Image?
          @Published var imageState: ImageState = .empty
          @Published var imageSelection: PhotosPickerItem? = nil {
              didSet {
                  if let imageSelection = imageSelection {
                      let progress = loadTransferable(from: imageSelection)
                      imageState = .loading(progress)
                  } else {
                      imageState = .empty
                  }
              }
          }
      
          func applyFilter() { /* Apply your filter */}
      
          private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
              return imageSelection.loadTransferable(type: Image.self) { result in
                  DispatchQueue.main.async {
                      guard imageSelection == self.imageSelection else { return }
                      switch result {
                      case .success(let image?):
                          self.imageState = .success(image)
                      case .success(nil):
                          self.imageState = .empty
                      case .failure(let error):
                          self.imageState = .failure(error)
                      }
                  }
              }
          }
      }
    • 26:17 - Context Menu

      import PhotosUI
      import CoreTransferable
      
      struct ContentView: View {
          @ObservedObject var viewModel: FilterModel = .shared
      
          var body: some View {
              NavigationStack {
                  Gallery()
                      .navigationTitle("Birthday Filter")
                      .toolbar {
                          PhotosPicker(
                              selection: $viewModel.imageSelection,
                              matching: .images
                          ) {
                              Label("Pick a photo", systemImage: "plus.app")
                          }
                          if let item = viewModel.processedImage {
                              ShareLink(
                                  item: item, preview: SharePreview("Birthday Effects"))
                          }
                          Button {
                              viewModel.applyFilter()
                          } label: {
                              Label("Apply Filter", systemImage: "camera.filters")
                          }
                      }
                      .contextMenu {
                          Button {
                              viewModel.applyFilter()
                          } label: {
                              Label("Apply Filter", systemImage: "camera.filters")
                          }
                          if let item = viewModel.processedImage {
                              ShareLink(
                                  item: item, preview: SharePreview("Birthday Effects"))
                          }
                          Button(role: .destructive) {
                              viewModel.deleteCurrentPhoto()
                          } label: {
                              Label("Delete", systemImage: "trash")
                          }
                      }
              }
          }
      }
      
      struct Gallery: View {
          @ObservedObject var viewModel: FilterModel = .shared
      
          var body: some View {
              VStack {
                  switch viewModel.imageState {
                  case .success(let image):
                      image
                          .resizable()
                          .aspectRatio(contentMode: .fill)
                          .draggable(image)
                  case .loading:
                      ProgressView()
                  case .empty:
                      Text("No Photo \(Image(systemName: "photo"))")
                          .font(.title2)
                          .fontWeight(.semibold)
                      Text("Drag and drop a photo or press\n \(Image(systemName: "plus.app")) to choose a photo manually.")
                          .foregroundColor(.secondary)
                          .multilineTextAlignment(.center)
                  case .failure:
                      Image(systemName: "exclamationmark.triangle.fill")
                          .font(.system(size: 40))
                          .foregroundColor(.white)
                  }
              }
              .padding()
          }
      }
      
      @MainActor
      class FilterModel: ObservableObject {
          static let shared = FilterModel()
      
          enum ImageState {
              case empty, loading(Progress), success(Image), failure(Error)
          }
      
          @Published private(set) var processedImage: Image?
          @Published var imageState: ImageState = .empty
          @Published var imageSelection: PhotosPickerItem? = nil {
              didSet {
                  if let imageSelection = imageSelection {
                      let progress = loadTransferable(from: imageSelection)
                      imageState = .loading(progress)
                  } else {
                      imageState = .empty
                  }
              }
          }
      
          func applyFilter() { /* Apply your filter */}
      
          func deleteCurrentPhoto() {}
      
          private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
              return imageSelection.loadTransferable(type: Image.self) { result in
                  DispatchQueue.main.async {
                      guard imageSelection == self.imageSelection else { return }
                      switch result {
                      case .success(let image?):
                          self.imageState = .success(image)
                      case .success(nil):
                          self.imageState = .empty
                      case .failure(let error):
                          self.imageState = .failure(error)
                      }
                  }
              }
          }
      }
    • 26:50 - Drop destination

      import PhotosUI
      import CoreTransferable
      
      struct ContentView: View {
          @ObservedObject var viewModel: FilterModel = .shared
      
          var body: some View {
              NavigationStack {
                  Gallery()
                      .navigationTitle("Birthday Filter")
                      .toolbar {
                          PhotosPicker(
                              selection: $viewModel.imageSelection,
                              matching: .images
                          ) {
                              Label("Pick a photo", systemImage: "plus.app")
                          }
                          if let item = viewModel.processedImage {
                              ShareLink(
                                  item: item, preview: SharePreview("Birthday Effects"))
                          }
                          Button {
                              viewModel.applyFilter()
                          } label: {
                              Label("Apply Filter", systemImage: "camera.filters")
                          }
                      }
                      .contextMenu {
                          Button {
                              viewModel.applyFilter()
                          } label: {
                              Label("Apply Filter", systemImage: "camera.filters")
                          }
                          if let item = viewModel.processedImage {
                              ShareLink(
                                  item: item, preview: SharePreview("Birthday Effects"))
                          }
                          Button(role: .destructive) {
                              viewModel.deleteCurrentPhoto()
                          } label: {
                              Label("Delete", systemImage: "trash")
                          }
                      }
                      .dropDestination(payloadType: Image.self) { receivedImages, location in
                          guard let image = receivedImages.first else {
                              return false
                          }
                          viewModel.imageState = .success(image)
                          return true
                      }
              }
          }
      }
      
      struct Gallery: View {
          @ObservedObject var viewModel: FilterModel = .shared
      
          var body: some View {
              VStack {
                  switch viewModel.imageState {
                  case .success(let image):
                      image
                          .resizable()
                          .aspectRatio(contentMode: .fill)
                          .draggable(image)
                  case .loading:
                      ProgressView()
                  case .empty:
                      Text("No Photo \(Image(systemName: "photo"))")
                          .font(.title2)
                          .fontWeight(.semibold)
                      Text("Drag and drop a photo or press\n \(Image(systemName: "plus.app")) to choose a photo manually.")
                          .foregroundColor(.secondary)
                          .multilineTextAlignment(.center)
                  case .failure:
                      Image(systemName: "exclamationmark.triangle.fill")
                          .font(.system(size: 40))
                          .foregroundColor(.white)
                  }
              }
              .padding()
          }
      }
      
      @MainActor
      class FilterModel: ObservableObject {
          static let shared = FilterModel()
      
          enum ImageState {
              case empty, loading(Progress), success(Image), failure(Error)
          }
      
          @Published private(set) var processedImage: Image?
          @Published var imageState: ImageState = .empty
          @Published var imageSelection: PhotosPickerItem? = nil {
              didSet {
                  if let imageSelection = imageSelection {
                      let progress = loadTransferable(from: imageSelection)
                      imageState = .loading(progress)
                  } else {
                      imageState = .empty
                  }
              }
          }
      
          func applyFilter() { /* Apply your filter */}
      
          func deleteCurrentPhoto() {}
      
          private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
              return imageSelection.loadTransferable(type: Image.self) { result in
                  DispatchQueue.main.async {
                      guard imageSelection == self.imageSelection else { return }
                      switch result {
                      case .success(let image?):
                          self.imageState = .success(image)
                      case .success(nil):
                          self.imageState = .empty
                      case .failure(let error):
                          self.imageState = .failure(error)
                      }
                  }
              }
          }
      }
    • 28:15 - Shape Styles: CalendarIcon

      struct CalendarIcon: View {
          var body: some View {
              VStack {
                  Image(systemName: "calendar")
                      .font(.system(size: 80, weight: .medium))
                  Text("June 6")
              }
              .background(in: Circle().inset(by: -20))
              .backgroundStyle(
                  .blue
                  .gradient
              )
              .foregroundStyle(.white.shadow(.drop(radius: 1, y: 1.5)))
              .padding(20)
          }
      }
    • 28:49 - Shape Styles: Icon Grid

      struct Icon: View {
          let systemSymbolName: String
          let color: Color
          let shadow: ShadowStyle
          var foregroundColor: Color = .white
      
          var body: some View {
              VStack {
                  Image(systemName: systemSymbolName)
                      .resizable()
                      .aspectRatio(1.0, contentMode: .fit)
                      .padding(2)
              }
              .background(in: Circle().inset(by: -20))
              .backgroundStyle(
                  color
                  .gradient
              )
              .foregroundStyle(foregroundColor.shadow(shadow))
              .padding(20)
          }
      }
      
      private let dropStyle = ShadowStyle.drop(radius: 1, y: 1.5)
      private let innerStyle = ShadowStyle.inner(radius: 1.5)
      
      let icons: [Icon]  = [
          Icon(systemSymbolName: "person", color: .red, shadow: dropStyle),
          Icon(systemSymbolName: "basketball", color: .orange, shadow: dropStyle),
          Icon(systemSymbolName: "globe.central.south.asia", color: .yellow, shadow: innerStyle),
          Icon(systemSymbolName: "carrot", color: .green, shadow: innerStyle, foregroundColor: .orange),
          Icon(systemSymbolName: "sailboat", color: .mint, shadow: innerStyle),
          Icon(systemSymbolName: "figure.open.water.swim", color: .teal, shadow: dropStyle),
          Icon(systemSymbolName: "ladybug.fill", color: .cyan, shadow: innerStyle),
          Icon(systemSymbolName: "calendar", color: .blue, shadow: dropStyle),
          Icon(systemSymbolName: "moon.stars", color: .indigo, shadow: dropStyle),
          Icon(systemSymbolName: "brain.head.profile", color: .purple, shadow: innerStyle),
          Icon(systemSymbolName: "birthday.cake", color: .pink, shadow: dropStyle),
          Icon(systemSymbolName: "house.circle.fill", color: .white, shadow: dropStyle),
          Icon(systemSymbolName: "lizard", color: .brown, shadow: dropStyle),
          Icon(systemSymbolName: "flag.checkered", color: .black, shadow: dropStyle),
          Icon(systemSymbolName: "character.book.closed", color: .gray, shadow: dropStyle),
      ]
      
      struct IconGrid: View {
          var body: some View {
              Grid(horizontalSpacing: 16, verticalSpacing: 16) {
                  ForEach(0..<3) { i in
                      GridRow {
                          ForEach(0..<5) { j in
                              icons[i * 5 + j]
                          }
                      }
                  }
              }
              .background(.black.opacity(0.8))
          }
      }
    • 29:07 - Graphics: Dancing symbol grid

      // MARK: - Dancing Symbol Grid
      
      struct SymbolSquare: View {
          let color: Color
          let imageName: String
          var image: some View {
              Image(systemName: imageName)
                  .resizable()
                  .aspectRatio(contentMode: .fit)
                  .padding()
                  .frame(maxWidth: .infinity, maxHeight: .infinity)
          }
      
          var body: some View {
              image
                  .background {
                      RoundedRectangle(cornerRadius: 6, style: .continuous)
                          .fill(
                              .ellipticalGradient(
                                  color
                                      .gradient
                              )
                          )
                  }
          }
      }
      
      /// If `true`, the party will commence. 
      private let startTheParty = false
      
      private let partySymbols = ["party.popper", "balloon", "balloon.2", "birthday.cake"]
      
      struct DancingSymbolSquare: View {
          let color: Color
          let imageName: String
        
          /// Allows staggered dancing — doesn't look quite as nice.
          let seed: Int
          private let timer = Timer.publish(every: 0.234378662, on: .main, in: .default)
          @State private var cancellable: Cancellable? = nil
          @State private var heavy = false
          @State var fontSize = 20 as CGFloat
      
          var body: some View {
              SymbolSquare(color: color, imageName: imageName)
                  .font(.body.weight(heavy ? .black : .thin))
                  .onReceive(timer) { date in
                      if heavy {
                          withAnimation(.easeOut(duration: 0.468757324 - 0.1)) {
                              heavy.toggle()
                          }
                      } else {
                          withAnimation(.easeIn(duration: 0.1)) {
                              heavy.toggle()
                          }
                      }
                  }
                  .onAppear {
                      if startTheParty {
                          DispatchQueue.main.asyncAfter(deadline: .now()  + Double(seed) * 0.25) {
                              cancellable = timer.connect()
                          }
                      }
                  }
                  .drawingGroup(opaque: true)
          }
      }
      
      struct SymbolGrid: View {
          var body: some View {
              Grid {
                  GridRow {
                      DancingSymbolSquare(color: .yellow, imageName:partySymbols[0], seed: 0)
                      DancingSymbolSquare(color: .green, imageName: partySymbols[1], seed: 0)
                  }
      
                  GridRow {
                      DancingSymbolSquare(color: .indigo, imageName: partySymbols[2], seed: 0)
                      DancingSymbolSquare(color: .purple, imageName: partySymbols[3],  seed: 0)
                  }
              }
              .frame(maxWidth: .infinity, maxHeight: .infinity)
          }
      }
    • 30:15 - Graphics: Text transitions

      struct TextTransitionsView: View {
          @State private var expandMessage = true
          private let mintWithShadow: AnyShapeStyle = AnyShapeStyle(Color.mint.shadow(.drop(radius: 2)))
          private let primaryWithoutShadow: AnyShapeStyle = AnyShapeStyle(Color.primary.shadow(.drop(radius: 0)))
      
          var body: some View {
              Text("Happy Birthday SwiftUI!")
                  .font(expandMessage ? .largeTitle.weight(.heavy) : .body)
                  .foregroundStyle(expandMessage ? mintWithShadow : primaryWithoutShadow)
                  .onTapGesture { withAnimation { expandMessage.toggle() }}
                  .frame(maxWidth: expandMessage ? 160 : 250)
                  .drawingGroup()
                  .padding(20)
                  .background(.pink.opacity(0.3), in: RoundedRectangle(cornerRadius: 6))
          }
      }
    • 31:16 - Layout: Grid

      struct VIPDetailView: View {
          var body: some View {
              Grid {
                  GridRow {
                      NameHeadline()
                          .gridCellColumns(2)
                  }
                  GridRow {
                      CalendarIcon()
                      SymbolGrid()
                  }
              }
              .frame(width: 300, height: 300)
          }
      }
      
      struct NameHeadline: View {
          var body: some View {
              HStack {
                  Color.green.background(in: RoundedRectangle(cornerRadius: 8))
                      .frame(maxWidth: .infinity, maxHeight: .infinity)
                  VStack(alignment: .leading) {
                      Text("Franck Ndame Mpouli")
                          .font(.title2)
                          .foregroundStyle(.shadow(.drop(radius: 2, y: 3)))
                      Text("Party Planning Committee").bold()
                  }
              }
              .padding()
              .frame(maxWidth: .infinity, maxHeight: .infinity)
              .background(
                  .white.gradient,
                  in: RoundedRectangle(cornerRadius: 12, style: .continuous)
              )
          }
      }
      
      struct CalendarIcon: View {
          var body: some View {
              VStack {
                  Image(systemName: "calendar")
                      .font(.system(size: 80, weight: .medium))
                  Text("June 6")
              }
              .background(in: Circle().inset(by: -20))
              .backgroundStyle(
                  .blue
                  .gradient
              )
              .foregroundStyle(.white.shadow(dropStyle))
              .padding(20)
              .frame(maxWidth: .infinity, maxHeight: .infinity)
          }
      }
    • 32:04 - Layout: Seating Chart Layout

      // MARK: Custom Table Layout
      
      private let tableSize = CGSize(width: 130, height: 90)
      private let guestSize = CGSize(width: 40, height: 40)
      
      /// Which of 6 tables this view represents
      private struct TableViewLayoutKey: LayoutValueKey {
          static let defaultValue: Int? = nil
      }
      
      extension View {
          fileprivate func tableViewLayoutKey(_ value: Int) -> some View  {
              return layoutValue(key: TableViewLayoutKey.self, value: value)
          }
      }
      
      /// Which of 36 guests this view represents
      private struct GuestViewLayoutKey: LayoutValueKey {
          static let defaultValue: Int? = 0
      }
      
      extension View {
      
          /// Guests 1 - 36
          fileprivate func guestViewLayoutKey(_ value: Int) -> some View  {
              return layoutValue(key: GuestViewLayoutKey.self, value: value)
          }
      }
      
      let initials = [
      "Ju",
      "As",
      "Ma",
      "As",
      "Ly",
      "Ga",
      "Ni",
      "Ar",
      "Ca",
      "Do",
      "Je",
      "Ca",
      "Em",
      "Ma",
      "Ze",
      "Jo",
      "Da",
      "Sh",
      "Sa",
      "Pl",
      "Pa",
      "Sc",
      "Ma",
      "Je",
      "Li",
      "Ma",
      "Ta",
      "Je",
      "Cu",
      "Lu",
      "Ra",
      "Na",
      "Sa",
      "Pa",
      "Le",
      "Pi",
      ]
      
      struct SeatingChartView: View {
      
          /// If true, the guests will be positioned in "pods" of tables. No table will touch another table. Otherwise
          /// the guests will side in two longs rows.
          @State private var usePods = true
      
          var body: some View {
              ZStack(alignment: .bottomTrailing) {
                  GeometryReader { proxy in
                      SeatingLayout(usePods: usePods).callAsFunction {
                          TableView(tableNumber: 1)
                          TableView(tableNumber: 2)
                          TableView(tableNumber: 3)
                          TableView(tableNumber: 4)
                          TableView(tableNumber: 5)
                          TableView(tableNumber: 6)
                          ForEach(1..<37) { i in
                              SeatedGuestOption2(guestNumber: i - 1)
                          }
                      }
                      .animation(.default, value: proxy.size)
                  }
                  .background(.black.opacity(0.13))
                  Picker("Arrangement", selection: $usePods.animation()) {
                      Text("Pods").tag(true)
                      Text("Rows  ").tag(false)
                  }
                  .fixedSize()
                  .pickerStyle(.segmented)
                  .padding()
              }
          }
      }
      
      /// heh.
      struct TableView: View {
          let tableNumber: Int
      
          var body: some View {
              ZStack(alignment: .bottomTrailing) {
                  HStack {
                      Image(systemName: "table.furniture")
                          .background(.quaternary.shadow(.inner(radius: 1, y: 1.5)),
                                      in: Circle().inset(by: -8))
                          .padding(5)
                      Text("Table \(tableNumber)")
                  }
                  .foregroundStyle(.secondary)
                  .padding(8)
                  .frame(width: tableSize.width, height: tableSize.height)
                  #if os(macOS) || os(iOS)
                  .background(.regularMaterial.shadow(.drop(radius: 1, y: 1.5)),
                              in: RoundedRectangle(cornerRadius: 12, style: .continuous))
                  #endif
              }
      
              .tableViewLayoutKey(tableNumber)
          }
      }
      
      private let colors: [Color] = [
          .red, .orange, .yellow, .green, .mint, .teal, .cyan, .blue,
          .indigo, .purple, .pink, .gray, .black, .white, .brown,
          .red, .orange, .yellow, .green, .mint, .teal, .cyan, .blue,
          .indigo, .purple, .pink, .gray, .black, .white, .brown, .red,
          .orange, .yellow, .green, .mint, .teal, .cyan
      ]
      
      struct SeatedGuest: View {
      
          let guestNumber: Int
      
          var body: some View {
              Image(systemName: "person")
                  .resizable()
                  .aspectRatio(contentMode: .fit)
                  .padding(9)
                  .background(in: Circle())
                  .backgroundStyle(
                      colors[guestNumber].gradient
                  )
                  .foregroundStyle(guestNumber == 13 ? .black : .white)
                  .frame(width: 40, height: 40)
                  .guestViewLayoutKey(guestNumber + 1)
          }
      }
      
      struct SeatedGuestOption2: View {
          let guestNumber: Int
      
          var body: some View {
              Circle()
                  .stroke(colors[guestNumber], style: StrokeStyle(lineWidth: 3))
                  .background(.white.gradient, in: Circle())
                  .frame(width: guestSize.width, height: guestSize.height)
                  .guestViewLayoutKey(guestNumber + 1)
                  .overlay {
                      Text(initials[guestNumber])
                          .foregroundColor(.secondary)
                          .font(.callout)
      
                  }
          }
      }
      
      struct SeatingChartView_Previews: PreviewProvider {
          static var previews: some View {
              SeatingChartView()
                  .frame(width: 600, height: 600)
          }
      }
      
      struct SeatingLayout: Layout {
      
          /// If true, the guests will be positioned in "pods" of tables. No table will touch another table. Otherwise
          /// the guests will side in two longs rows.
          let usePods: Bool
      
          struct Cache {
              ///  The width proposed to the view. We assume a certain height, otherwise, overlapping views
              var width: CGFloat?
          }
      
          func sizeThatFits(
              proposal: ProposedViewSize,
              subviews: LayoutSubviews,
              cache: inout Cache
          ) -> CGSize {
              cache.width = proposal.width
              return proposal.replacingUnspecifiedDimensions()
          }
      
          func makeCache(subviews: Subviews) -> Cache { Cache() }
      
          func placeSubviews(in bounds: CGRect,
                             proposal: ProposedViewSize,
                             subviews: Subviews,
                             cache: inout Cache) {
              guard let width = cache.width else { return }
      
              /// Helper function: Place 6 guests around all edges of a table.
              func seat(_ guests: [LayoutSubview], around table: CGRect) {
                  guests[0].place(
                      at: .init(
                          x: table.origin.x + 3 - guestSize.width,
                          y: table.origin.y + (table.height / 2.0) - (guestSize.height / 2.0)),
                      proposal: .infinity)
                  guests[1].place(
                      at: .init(
                          x: table.origin.x + (table.width / 4.0) - guestSize.width / 2.0,
                          y: table.origin.y + 5 - guestSize.height),
                      proposal: .infinity)
                  guests[2].place(
                      at: .init(
                          x: table.origin.x + table.width * 0.75 - guestSize.width / 2.0,
                          y: table.origin.y + 5 - guestSize.height),
                      proposal: .infinity)
                  guests[3].place(
                      at: .init(
                          x: table.maxX - 5,
                          y: table.origin.y + (table.height / 2.0) - (guestSize.height / 2.0)),
                      proposal: .infinity)
                  guests[4].place(
                      at: .init(
                          x: table.origin.x + table.width * 0.75 - guestSize.width / 2.0,
                          y: table.maxY - 5),
                      proposal: .infinity)
                  guests[5].place(
                      at: .init(
                          x: table.origin.x + (table.width / 4.0) - guestSize.width / 2.0,
                          y: table.maxY - 5),
                      proposal: .infinity)
              }
      
              /// Helper function: Place 6 guests, dining hall style (not along the shorter sides of a table)
              func seat(_ guests: [LayoutSubview], along table: CGRect) {
                  guests[0].place(
                      at: .init(
                          x: table.minX + tableSize.width / 3 - guestSize.width - 4,
                          y: table.origin.y + 5 - guestSize.height),
                      proposal: .infinity)
                  guests[1].place(
                      at: .init(
                          x: table.minX + tableSize.width * 2/3 - guestSize.width - 4,
                          y: table.origin.y + 5 - guestSize.height),
                      proposal: .infinity)
                  guests[2].place(
                      at: .init(
                          x: table.minX + tableSize.width - guestSize.width - 4,
                          y: table.origin.y + 5 - guestSize.height),
                      proposal: .infinity)
                  guests[3].place(
                      at: .init(
                          x: table.minX + tableSize.width / 3 - guestSize.width - 4,
                          y: table.maxY - 5),
                      proposal: .infinity)
                  guests[4].place(
                      at: .init(
                          x: table.minX + tableSize.width * 2/3 - guestSize.width - 4,
                          y: table.maxY - 5),
                      proposal: .infinity)
                  guests[5].place(
                      at: .init(
                          x: table.minX + tableSize.width - guestSize.width - 4,
                          y: table.maxY - 5),
                      proposal: .infinity)
              }
      
              // Get tables
              let table1 = subviews.first(where: { $0[TableViewLayoutKey.self] == 1 })!
              let table2 = subviews.first(where: { $0[TableViewLayoutKey.self] == 2 })!
              let table3 = subviews.first(where: { $0[TableViewLayoutKey.self] == 3 })!
              let table4 = subviews.first(where: { $0[TableViewLayoutKey.self] == 4 })!
              let table5 = subviews.first(where: { $0[TableViewLayoutKey.self] == 5 })!
              let table6 = subviews.first(where: { $0[TableViewLayoutKey.self] == 6 })!
      
              // Get guests
              let table1Guests = subviews
                  .filter {
                      guard let guestNumber = $0[GuestViewLayoutKey.self] else { return false }
                      return guestNumber >= 1 && guestNumber <= 6
                  }
              let table2Guests = subviews
                  .filter {
                      guard let guestNumber = $0[GuestViewLayoutKey.self] else { return false }
                      return guestNumber >= 7 && guestNumber <= 12
                  }
              let table3Guests = subviews
                  .filter {
                      guard let guestNumber = $0[GuestViewLayoutKey.self] else { return false }
                      return guestNumber >= 13 && guestNumber <= 18
                  }
              let table4Guests = subviews
                  .filter {
                      guard let guestNumber = $0[GuestViewLayoutKey.self] else { return false }
                      return guestNumber >= 19 && guestNumber <= 24
                  }
              let table5Guests = subviews
                  .filter {
                      guard let guestNumber = $0[GuestViewLayoutKey.self] else { return false }
                      return guestNumber >= 25 && guestNumber <= 30
                  }
              let table6Guests = subviews
                  .filter {
                      guard let guestNumber = $0[GuestViewLayoutKey.self] else { return false }
                      return guestNumber >= 31 && guestNumber <= 36
                  }
      
              if usePods {
                  let table1Origin = CGPoint(x: 60, y: 120)
                  let table2Origin = CGPoint(x: 200, y: 280)
                  let table3Origin = CGPoint(x: 50, y: 450)
                  let table4Origin = CGPoint(x: 300, y: 120)
                  let table5Origin = CGPoint(x: 440, y: 280)
                  let table6Origin = CGPoint(x: 290, y: 450)
                  table1.place(at: table1Origin, proposal: .infinity)
                  table2.place(at: table2Origin, proposal: .infinity)
                  table3.place(at: table3Origin, proposal: .infinity)
                  table4.place(at: table4Origin, proposal: .infinity)
                  table5.place(at: table5Origin, proposal: .infinity)
                  table6.place(at: table6Origin, proposal: .infinity)
                  seat(table1Guests, around: CGRect(origin: table1Origin, size: tableSize))
                  seat(table2Guests, around: CGRect(origin: table2Origin , size: tableSize))
                  seat(table3Guests, around: CGRect(origin: table3Origin, size: tableSize))
                  seat(table4Guests, around: CGRect(origin: table4Origin, size: tableSize))
                  seat(table5Guests, around: CGRect(origin: table5Origin , size: tableSize))
                  seat(table6Guests, around: CGRect(origin: table6Origin, size: tableSize))
              } else {
                  let table1Origin = CGPoint(x: width / 2.0 - 6 - tableSize.width * 1.5, y: 130)
                  let table2Origin = CGPoint(x: table1Origin.x + tableSize.width + 6, y: 130)
                  let table3Origin = CGPoint(x: table2Origin.x + tableSize.width + 6, y: 130)
                  let table4Origin = CGPoint(x: width / 2.0 - 6 - tableSize.width * 1.5, y: 360)
                  let table5Origin = CGPoint(x: table1Origin.x + tableSize.width + 6, y: 360)
                  let table6Origin = CGPoint(x: table2Origin.x + tableSize.width + 6, y: 360)
                  table1.place(at: table1Origin, proposal: .infinity)
                  table2.place(at: table2Origin, proposal: .infinity)
                  table3.place(at: table3Origin, proposal: .infinity)
                  table4.place(at: table4Origin, proposal: .infinity)
                  table5.place(at: table5Origin, proposal: .infinity)
                  table6.place(at: table6Origin, proposal: .infinity)
                  seat(table1Guests, along: CGRect(origin: table1Origin, size: tableSize))
                  seat(table2Guests, along: CGRect(origin: table2Origin , size: tableSize))
                  seat(table3Guests, along: CGRect(origin: table3Origin, size: tableSize))
                  seat(table4Guests, along: CGRect(origin: table4Origin, size: tableSize))
                  seat(table5Guests, along: CGRect(origin: table5Origin , size: tableSize))
                  seat(table6Guests, along: CGRect(origin: table6Origin, size: tableSize))
              }
          }
      }
    • 32:50 - AnyLayout invitation

      import SwiftUI
      import GameplayKit
      import Combine
      
      @main
      struct InvitationApp: App {
          var body: some Scene {
              WindowGroup {
                  PolygonDesignerView()
                      .environmentObject(PolygonModel())
                  #if os(iOS)
                      .statusBar(hidden: true)
                  #endif
                      .edgesIgnoringSafeArea(.all)
              }
          }
      }
      
      // MARK: Views
      
      /// A view that arranges polygons in a grid, or a custom, scattered layout.
      private struct DynamicPolygonView: View {
          @EnvironmentObject var model: PolygonModel
          @Binding var cycleLayouts: Bool
      
          private var sideLength: Int {
              Int(CGFloat(model.polygonGeometries.count).squareRoot())
          }
      
          /// Timer whose ticking dictates how often to regenerate and animate-to a new scattered layout.
          /// - Note: The layout will only transition if `cycleLayouts` is `true`.
          private let layoutChangingTimer = Timer
              .publish(every: 1.2, on: .current, in: .default).autoconnect()
      
          /// Animation used to transition layouts
          private let animation = Animation.easeInOut(duration: 1.3)
      
          /// Timer that ticks at 128 beats per minute, matching the beat of the song in the WWDC session.
          let musicBeatTimer = Timer
              .publish(every: 0.234378662, tolerance: 0,  on: .main, in: .default)
      
          @State private var musicBeatTimerCancellable: (any Cancellable)? = nil
      
          /// Whether or not the font should be rendered heavy.
          @State private var heavy: Bool = false
      
          @State private var scatteredLayout = newScatteredLayout(
              Date(timeIntervalSince1970: 0)
          )
      
          /// By providing a seed value, the `ScatteredLayout` struct will know when to bust its cache and
          /// generate new layout data.
          private static func newScatteredLayout(_ seed: Date) -> ScatteredLayout {
              ScatteredLayout(count: PolygonModel.total,
                              seed: seed.timeIntervalSinceReferenceDate,
                              textAvoidanceRect: CGRect(
                                  x: 152,
                                  y: 245,
                                  width: 220,
                                  height: 40)
              )
          }
      
          var body: some View {
              let layout = model.usesGridLayout
              ? AnyLayout(Grid(alignment: .center,
                               horizontalSpacing: 0,
                               verticalSpacing: 0))
              : AnyLayout(scatteredLayout)
      
              ZStack(alignment: .center) {
                  Label(title:  {
                      Text("You're Invited")
                  }, icon: { Image(systemName: "party.popper.fill")})
                  .font(.system(size:100).weight(heavy ? .black : .thin))
                  .onTapGesture {
                      musicBeatTimerCancellable = musicBeatTimer.connect()
                  }
                  .zIndex(-1)
      
                  layout {
                      ForEach((0..<sideLength), id: \.self) { row in
                          GridRow { // GridRow is a no-op in non-Grid layouts
                              ForEach((0..<sideLength), id: \.self) { column in
                                  let polygon = model
                                      .polygonGeometries[sideLength * row + column]
                                  PolygonView(polygonGeometry: polygon)
                                      .polygonViewLayoutKey(polygon)
                              }
                          }
                      }
                  }
              }
              .drawingGroup()
              .frame(maxWidth: .infinity, maxHeight: .infinity)
              .onReceive(musicBeatTimer) { date in
                  if heavy {
                      // Transitioning to a thin font happens slowly
                      withAnimation(.easeOut(duration: 0.468757324 - 0.1)) {
                          heavy.toggle()
                      }
                  } else {
                      // Transitioning to thick happens quickly, to give the
                      // appearance of a "strong" downbeat
                      withAnimation(.easeIn(duration: 0.1)) {
                          heavy.toggle()
                      }
                  }
              }
              .onReceive(layoutChangingTimer) { date in
                  guard cycleLayouts else { return }
                  withAnimation(animation) {
                      scatteredLayout = DynamicPolygonView.newScatteredLayout(date)
                  }
      
              }
          }
      }
      
      private struct PolygonDesignerView: View {
          @EnvironmentObject var model: PolygonModel
          @State var cycleLayouts = false
          @State var hideDesignerView = true
      
          var body: some View {
              ZStack(alignment: .bottom) {
                  DynamicPolygonView(cycleLayouts: $cycleLayouts)
                      .onTapGesture(count: 2) {
                          withAnimation {
                              hideDesignerView.toggle()
                          }
                      }
                  ControlView(cycleLayouts: $cycleLayouts)
                      .padding()
                      .background(.thickMaterial)
                      .offset(CGSize(width: 0, height: hideDesignerView ? 300 : 0))
              }
          }
      }
      
      /// Tunes the parameters of a `PolygonModel`
      private struct ControlView: View {
      
          /// The instance `self` tunes the parameters of.
          @EnvironmentObject var model: PolygonModel
      
          /// Can be used by a parent view to cycle through instances of layouts.
          @Binding var cycleLayouts: Bool
      
          var body: some View {
              VStack {
                  Button("Reset", action: model.reset)
                  let layout = HStack()
                  layout {
                      Toggle("Tiled", isOn: Binding(get: {
                          model.tiled
                      }, set: { tile in
                          // After toggled, wait 5 seconds, then transition back to a
                          // scattered layout
                          DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                              withAnimation(.linear(duration: 1.4)) {
                                  model.usesGridLayout = false
                                  model.drawAsRandomPolygons = true
                              }
                          }
      
                          withAnimation(.linear(duration: 1.8)) {
                              model.usesGridLayout = tile
                              model.drawAsRandomPolygons = !tile
                          }
                      }))
      
                      Toggle("Cycle Layouts", isOn: $cycleLayouts)
                  }
              }
              .padding(2)
          }
      }
      
      // MARK: PolygonView
      
      /// Wraps a ``Polygon`` shape applying a fill.
      private struct PolygonView: View {
          var polygonGeometry: PolygonGeometry
      
          var body: some View {
              Polygon(polygonGeometry: polygonGeometry)
                  .fill(polygonGeometry.color)
          }
      }
      
      /// A Polygon shape that supports any number of sides as defined by `polygonGeometry`
      private struct Polygon: Shape {
          var polygonGeometry: PolygonGeometry
      
          typealias AnimatableData = AnimatableVector
      
          var animatableData: AnimatableVector {
              get { polygonGeometry.vectorPath }
              set { polygonGeometry.points = newValue.points }
          }
      
          func path(in rect: CGRect) -> Path {
              // Scale up the shape's path to fill as much space as it is given
              let path = polygonGeometry.path
              let boundingRect = path.boundingRect
      
              let xScale = rect.width / boundingRect.width
              let yScale = rect.height / boundingRect.height
      
              let translate = CGAffineTransform(
                  translationX: -boundingRect.origin.x * xScale,
                  y: -boundingRect.origin.y * yScale
              )
              let scale = CGAffineTransform(scaleX: xScale, y: yScale)
              return path.applying(scale.concatenating(translate))
          }
      
          func sizeThatFits(_ proposal: ProposedViewSize) -> CGSize {
              if proposal == .infinity {
                  // If proposed infinite space, use the preferred, absolute size.
                  return CGSize(width: polygonGeometry.sideLength,
                                height: polygonGeometry.sideLength)
              } else {
                  // If we don't have infinite space, assume we've been given all the
                  // space the parent view can afford, and take all of it.
                  return proposal.replacingUnspecifiedDimensions()
              }
          }
      }
      
      // MARK: ScatteredLayout
      
      private struct PolygonViewLayoutKey: LayoutValueKey {
          static let defaultValue: PolygonGeometry? = nil
      }
      
      extension View {
          fileprivate func polygonViewLayoutKey(_ value: PolygonGeometry)
          -> some View {
              return layoutValue(key: PolygonViewLayoutKey.self, value: value)
          }
      }
      
      /// ScatteredLayout assumes a certain standard size and lays out its views
      /// (tagged with `PolygonViewLayoutKey` data) such that they don't collide
      /// within that size. As the size grows, the shapes stay the same size,
      /// but get farther or closer.
      private struct ScatteredLayout: Layout {
      
          /// Cache data for a `ScatteredLayout`.
          struct Cache {
      
              /// Maps a `PolygonGeometry.id` to its position in a `standardSize`
              /// coordinate space.
              var rects: [UUID: CGRect]
      
              /// Used as a cache buster.
              var seed: TimeInterval?
          }
      
          /// The smallest size a view using this layout can be.
          private let minimumBaseSize: CGSize
      
          /// The base coordinate system this view assumes when laying out.
          private let standardSize: CGSize = CGSize(width: 500, height: 500)
      
          /// Clients can pass a value here and polygons won't be placed in that rect.
          var textAvoidanceRect: CGRect = .zero
      
          /// If different, we've been requested to bust the cache, and create a new
          /// one.
          /// - Note the cache can persist across different instances of a
          ///  `ScatteredLayout`
          private let seed: TimeInterval
      
          func sizeThatFits(
              proposal: ProposedViewSize,
              subviews: LayoutSubviews,
              cache: inout Cache
          ) -> CGSize {
              let proposedSize = proposal
                  .replacingUnspecifiedDimensions(by: minimumBaseSize)
              return CGSize(
                  width: proposedSize.width
                      .clamped(
                          to: minimumBaseSize.width..<CGFloat.greatestFiniteMagnitude
                      ),
                  height: proposedSize.height
                      .clamped(
                          to: minimumBaseSize.height..<CGFloat.greatestFiniteMagnitude
                      )
              )
          }
      
          init(count: Int, seed: TimeInterval, textAvoidanceRect: CGRect = .zero) {
              self.seed = seed
              minimumBaseSize = CGSize(width: CGFloat(count), height: CGFloat(count))
              self.textAvoidanceRect = textAvoidanceRect
          }
      
          func makeCache(subviews: Subviews) -> Cache {
              var cache: Cache =  Cache(rects: [:], seed: self.seed)
              var placedPolygons: [CGRect] = []
      
              for subview in subviews {
      
                  guard let polygon = subview[PolygonViewLayoutKey.self] else {
                      // This is the title text view, skip it.
                      continue
                  }
      
                  var subviewsPreferredSize = subview.sizeThatFits(.infinity)
                  var counter = 20
      
                  while counter > 0 {
                      counter -= 1
                      let randomX = CGFloat.random(in: 0..<standardSize.width)
                      let randomY: CGFloat
                      if randomX > textAvoidanceRect.minX
                          && randomX < textAvoidanceRect.maxX {
                          // Pick from either above or below the avoidance rect
                          if Bool.random() {
                              randomY = CGFloat.random(
                                  in: 0..<textAvoidanceRect.minY
                              )
                          } else {
                              randomY = CGFloat.random(
                                  in: textAvoidanceRect.maxY..<standardSize.height
                              )
                          }
                      } else {
                          randomY = CGFloat.random(in: 0..<standardSize.height)
                      }
      
                      let origin = CGPoint(x: randomX, y: randomY)
                      let rect = CGRect(origin: origin, size: subviewsPreferredSize)
      
                      if placedPolygons.allSatisfy({ placed in
                          !placed.intersects(rect)
                      }) && !rect.intersects(textAvoidanceRect) {
                          // The shape found a non-overlapping place to be. Lock in
                          // it's position
                          placedPolygons.append(rect)
                          cache.rects[polygon.id] =
                          CGRect(origin: origin,
                                 size: subviewsPreferredSize)
                          break
                      } else  {
                          if (counter == 0) {
                              if rect.intersects(textAvoidanceRect) {
                                  subviewsPreferredSize = .zero
                              }
                              placedPolygons.append(rect)
                              cache.rects[polygon.id] =
                              CGRect(origin: origin,
                                     size: subviewsPreferredSize)
                          }
                      }
                  }
              }
              return cache
          }
      
          func placeSubviews(in bounds: CGRect,
                             proposal: ProposedViewSize,
                             subviews: Subviews,
                             cache: inout Cache) {
              // We have the frame value cached (via makeCache())
              // for every view to be placed in a `standardSize` coordinate system.
              // Now we need to map that `standardSize` to the size was proposed.
              let proposedSize = proposal
                  .replacingUnspecifiedDimensions(by: minimumBaseSize)
              let xProposedToBaseRatio = proposedSize.width / standardSize.width
              let yProposedToBaseRatio = proposedSize.height / standardSize.height
      
              for subview in subviews {
                  guard let uuid = subview[PolygonViewLayoutKey.self]?.id, let rect =
                          cache.rects[uuid] else {
                      let desiredSize = subview.sizeThatFits(.zero)
                      let centered = desiredSize.centered(in: bounds)
                      subview.place(
                          at: centered.origin,
                          proposal: ProposedViewSize(
                              width: desiredSize.width,
                              height: desiredSize.height
                          )
                      )
                      continue
                  }
      
                  let mappedPoint = CGPoint(x: rect.origin.x * xProposedToBaseRatio,
                                            y: rect.origin.y * yProposedToBaseRatio)
      
                  subview.place(at: mappedPoint,
                                proposal: ProposedViewSize(width: rect.size.width,
                                                           height:rect.size.height)
                  )
              }
          }
      
          func updateCache(_ cache: inout Cache, subviews: Subviews) {
      
              // Bust the cache if we've been given a new seed value
              // or if our subviews have been swapped out from underneath us.
              if self.seed != cache.seed
                  || !cache.rects.contains(where: { (key: UUID, value: CGRect) in
                      subviews.first?[PolygonViewLayoutKey.self]?.id == key
                  })  {
                  cache = makeCache(subviews: subviews)
                  return
              }
          }
      
      }
      
      /// This struct facilitates animation of point-based `Path`s so long as said
      /// source and destination `Path` have an equal number of vertices.
      private struct AnimatableVector: VectorArithmetic {
      
          static var zero: AnimatableVector = AnimatableVector(points: [])
      
          private(set) var points: [CGPoint]
      
          var magnitudeSquared: Double {
              let squared = points.map { point in
                  CGPoint(x: point.x * point.x, y: point.y * point.y)
              }
              let sumOfSquares = squared.map { point in // dot product?
                  sqrt(point.x + point.y)
              }
              let sum = sumOfSquares.reduce(0, +)
              return Double(sum)
          }
      
          /// Facilitates a valid `.zero` value, no matter the dimension of the vector
          subscript(safe index: Int) -> CGPoint {
              return (self.points.count <= index) ? .zero : points[index]
          }
      
          static func - (lhs: AnimatableVector, rhs: AnimatableVector)
          -> AnimatableVector {
              let negated = rhs.points.map { CGPoint(x: -$0.x, y: -$0.y) }
              return lhs + AnimatableVector(points: negated)
          }
      
          static func + (lhs: AnimatableVector, rhs: AnimatableVector)
          -> AnimatableVector {
              var output: [CGPoint] = []
              for i in 0..<lhs.points.count {
                  output.append(CGPoint(x: lhs[safe: i].x + rhs[safe: i].x,
                                        y:lhs[safe: i].y + rhs[safe: i].y ))
              }
              return AnimatableVector(points: output)
          }
      
          mutating func scale(by rhs: Double) {
              points = points.map { CGPoint(x: $0.x * CGFloat(rhs),
                                            y: $0.y * CGFloat(rhs)) }
          }
      }
      
      // MARK: Random Polygon Generation & Geometry
      
      private let mean: Float = 10
      private let deviation: Float = 3
      private let gaussian = GKGaussianDistribution(
          randomSource: GKARC4RandomSource(),
          mean: mean,
          deviation: deviation)
      
      /// Factory type for creating points describing a random Polygon
      private struct PolygonGeometry: Identifiable, Equatable, Hashable {
      
          /// The horizontal and vertical side lengths of the polygon's bounding box.
          let sideLength: CGFloat
      
          /// A constant count of the total points that comprise this
          /// `PolygonGeometry`'s path. Clients can set `points` to a new value, but
          /// the new value should have the same `count` for smooth `Path` animations
          let numberOfVertices: Int
      
          /// Supports animation of point-based `Path`s by providing an array of
          /// points that can be interpolated.
          var vectorPath: AnimatableVector {
              AnimatableVector(points: points)
          }
      
          /// If `false`, this instance will present itself as a rectangular shape
          /// (not necessarily with 4 vertices) that fills available space.
          private(set) var drawsAsPolygon: Bool = true
      
          /// Points describing the `Path` used to render `self`.
          var points: [CGPoint] {
              willSet {
                  assert(points.count == polygonPathPoints.count)
              }
          }
      
          /// Delineate the path of the random polygon.
          private let polygonPathPoints: [CGPoint]
      
          let color: Color = [
              Color(red: 0.73, green: 0.20, blue: 0.20),
              Color(red: 0.95, green: 0.66, blue: 0.24),
              Color(red: 0.14, green: 0.29, blue: 0.49),
              Color(red: 0.46, green: 0.76, blue: 0.67),
              Color(red: 0.30, green: 0.33, blue: 0.22),
              Color(red: 0.49, green: 0.55, blue: 0.64),
              Color(red: 0.92, green: 0.53, blue: 0.30),
              Color(red: 0.20, green: 0.45, blue: 0.55),
              Color(red: 0.41, green: 0.45, blue: 0.45),
              Color(red: 0.87, green: 0.67, blue: 0.61)
          ].randomElement()!
      
          private var spikiness: CGFloat = 0.2
          private var irregularity: CGFloat = 0.2
      
          let id = UUID()
      
          /// Owning `Shape` instances should use this to draw.
          var path: Path { Path(from: points) }
      
          init(pointsVector: [CGPoint], sideLength: CGFloat) {
              self.numberOfVertices = pointsVector.count
              self.points = pointsVector
              self.polygonPathPoints = points
              self.sideLength = sideLength
          }
      
          func drawn(asRandomizedPolygon: Bool) -> Self {
              var copy = self
              copy.drawsAsPolygon = asRandomizedPolygon
              copy.points = asRandomizedPolygon
              ? copy.polygonPathPoints
              : CGRect(x: 0, y: 0, width: 1, height: 1)
                  .pointSequence(of: copy.numberOfVertices)
              return copy
          }
      
          func hash(into hasher: inout Hasher) {
              hasher.combine(id)
          }
      }
      
      /// A namespace around functionality to generate a  path drawn in a 1x1 square
      /// with configurable "irregularity" and "spikiness".
      /// The closer both are to zero, the closer the generated polygon is to a
      /// [regular polygon](https://mathworld.wolfram.com/RegularPolygon.html)
      private enum UnitPolygonGeometryFactory {
      
          /// The maximum possible radius. A value of 0.5 restricts the algorithm
          /// to the unit square.
          private static let maxRadius: CGFloat = 0.5
      
          /// A — by no means definitive — algorithm for creating an arbitrary
          /// polygon of `vertexCount` vertices
          /// - Parameters:
          ///   - vertexCount: How many vertices (and edges) the polygon will have
          ///   - irregularity: A subjective term for how "irregular" the polygon is.
          ///   A fully regular polygon has all equal sides, assuming 0 `spikinesss`.
          ///   - spikiness: A subjective term for how "spiky" the polygon is.
          ///   A polygon with high spikiness will have more vertices closer and
          ///   farther from where the vertex would be on a regular polygon.
          /// - Returns: An array of points representing the point-based path of
          /// the polygon
          static func random(vertexCount: Int,
                             irregularity: CGFloat = 0.2,
                             spikiness: CGFloat = 0.2)
          -> [CGPoint] {
      
              let floatVertices = CGFloat(vertexCount)
      
              // Irregularity is how much we're willing to allow the angular steps to
              // vary from "perfect". For example, in a regular (all sides equal)
              // six-sided polygon, each angular step is 2𝜋 / 6. Irregularity
              // defines the range that value can take, centered around a mean of
              // 2𝜋 / 6. We accept an irregularity between 0 and 1, and then
              // scale it for how much that represents out of a circle's radians.
              let scaledIrregularity = irregularity * 2.0 * CGFloat.pi / floatVertices
      
              // Spikiness describes how often we want to see values that are very
              // far from where a vertex of a regular polygon would be. For example,
              // a high positive spikiness might push a vertex radially very far from
              // the center, leading to a big "spike". Meanwhile, a spikiness of 0
              // will yield more circular polygons.
              let denormalizedSpikiness = spikiness * maxRadius
      
              let gaussian = GKGaussianDistribution(
                  randomSource: GKARC4RandomSource(),
                  mean: Float(maxRadius * 1024),
                  deviation: Float(denormalizedSpikiness * 1024))
      
              // Generate the angular steps
              var raidanAngleSteps: [CGFloat] = []
      
              // Both of these measured in radians
              let minimumSliceWidth =
              (2.0 * CGFloat.pi / floatVertices) - scaledIrregularity
              let maximumSliceWidth =
              (2.0 * CGFloat.pi / floatVertices) + scaledIrregularity
      
              var sum: CGFloat = 0
      
              for _ in (0..<vertexCount) {
                  let radians = CGFloat
                      .random(in: minimumSliceWidth...maximumSliceWidth)
                  raidanAngleSteps.append(radians)
                  sum += radians
              }
      
              // Re-divide these steps so the point 0 and n+1 are the same.
              // I.e. if the random angle generation from the above loop yielded
              // more or less than 2𝜋 radians, reapportion those divisions to sum to
              // 2𝜋.
              let k = sum / (2 * CGFloat.pi)
              (0..<vertexCount).forEach { i in
                  raidanAngleSteps[i] /= k
              }
      
              let maximumPossibleGaussianSample = CGFloat(
                  gaussian.mean + Float(denormalizedSpikiness * 1024)*3
              )
      
              // Finally, make all of the normalized points within a 1x1 square
              // Unlike the unit circle of traditional geometry, because (0, 0) is in
              // the top left, (0.5, 0.5) is in the middle. Thus, positively
              // incrementing the angle moves us clockwise around the circle
              var points: [CGPoint] = []
              let center = CGPoint(x: maxRadius, y: maxRadius)
              var cumulativeAngle: CGFloat = 0.0
              for i in (0..<Int(vertexCount)) {
      
                  // * 2 to keep the sample <= 0.5 (`maxRadius)
                  let radiusForPoint = CGFloat(gaussian.nextInt())
                  / (maximumPossibleGaussianSample * 2)
      
                  let x = center.x + radiusForPoint * cos(cumulativeAngle)
                  let y = center.y + radiusForPoint * sin(cumulativeAngle)
                  points.append(CGPoint(x: x, y: y))
      
                  cumulativeAngle += raidanAngleSteps[i]
              }
              return points
          }
      }
      
      // MARK: Observable Polygon Model
      
      /// A `PolygonModel` describes a collection of randomized ``Polygons`` that
      /// can be laid out by `AnyLayout` type.
      private class PolygonModel: ObservableObject {
      
          static let total = (maxSides - minSides + 1) * polygonsPerSideCount
      
          /// The minimum sides the randomly generated sides will have
          private static let minSides = 4
      
          /// The maximum sides the randomly generated sides will have
          private static let maxSides = 7
      
          /// The number of randomly generated polygons to make _per side length_.
          private static let polygonsPerSideCount = 32
      
          /// All `PolygonGeometry`s that are laid out with `scatteredLayout`
          @Published var polygonGeometries: [PolygonGeometry] = makeGeometries()
      
          /// If `true`, `self` is expressing a grid layout with rectangular tiles.
          var tiled: Bool { usesGridLayout && !drawAsRandomPolygons }
      
          /// If `true`, ignore `scatteredLayout` and instead use a `Grid` layout
          @Published var usesGridLayout: Bool = false
      
          /// If `true`, `polygonGeometries` draw themselves as randomized polygons.
          /// If false, a rectangle that fills all available space.
          @Published var drawAsRandomPolygons: Bool = true {
              didSet {
                  polygonGeometries = polygonGeometries.map {
                      $0.drawn(asRandomizedPolygon: drawAsRandomPolygons)
                  }
              }
          }
      
          /// Tunable by clients to experiment with different values.
          let spikiness: CGFloat = 0.2
          /// Tunable by clients to experiment with different values.
          let irregularity: CGFloat = 0.2
      
          /// Creates many ``PolygonGeometry`` instances with the given parameters.
          /// - Parameters:
          ///   - irregularity: A subjective term for how "irregular" the polygon is.
          ///   A fully regular polygon has all equal sides, assuming 0 `spikinesss`.
          ///   - spikiness: A subjective term for how "spiky" the polygon is.
          ///   A polygon with high spikiness will have more vertices closer and
          ///   farther from where the vertex would be on a regular polygon.
          /// - Returns: An array of `n` polygons where `n` is defined by the
          ///  `PolygonModel` class.
          private static func makeGeometries(
              irregularity: CGFloat = 0.3,
              spikiness: CGFloat = 0.3) -> [PolygonGeometry] {
                  var scales: Array<CGFloat> = polygonSizeRatios
                      .reduce(into: []) { partialResult, sizeRatio in
                          let (size, percentage) = sizeRatio
                          let scalesToMake = Int(ceil(percentage * CGFloat(total)))
                          partialResult.append(contentsOf: (0..<scalesToMake)
                              .map { _ in CGFloat.random(in: size.sizeRange) })
                      }.shuffled()
      
                  return (minSides...maxSides).flatMap { vertexCount in
                      return (0..<polygonsPerSideCount).map { _ in
                          let unitPolygon = UnitPolygonGeometryFactory
                              .random(vertexCount: vertexCount,
                                      irregularity: irregularity,
                                      spikiness: spikiness)
                          let polygonGeometry = PolygonGeometry(
                              pointsVector: unitPolygon,
                              sideLength: scales.removeFirst())
                          return polygonGeometry
                      }
                  }.shuffled()
              }
      
          /// Complete remove and regenerate all model data.
          func reset() {
              polygonGeometries.removeAll(keepingCapacity: true)
              polygonGeometries = PolygonModel.makeGeometries(
                  irregularity: irregularity,
                  spikiness: spikiness
              )
          }
      }
      
      private extension PolygonModel {
      
          /// Use a sampling of various sized polygons
          enum PieceSize: Hashable {
              case tiny
              case small
              case medium
              case large
      
              /// The range for the side length of the bounding rect of a polygon
              var sizeRange: ClosedRange<CGFloat> {
                  switch self {
                  case .tiny:
                      return 16.0...25.0
                  case .small:
                      return 25.0...40.0
                  case .medium:
                      return 40.0...50.0
                  case .large:
                      return 50.0...65.0
                  }
              }
          }
      
          /// This dictionary denotes the ratio of sizes to use.
          /// - warning: Should sum to 100.
          private static let polygonSizeRatios: [PieceSize: CGFloat] =
          [
              .large: 0.15,
              .medium: 0.25,
              .small: 0.25,
              .tiny: 0.35
          ]
      }
      
      // MARK: - Utility Extensions
      
      extension FloatingPoint {
      
          /// - returns an instance of `Self` clamped to the ``ClosedRange``.
          func clamped(to limits: ClosedRange<Self>) -> Self {
              return min(max(self, limits.lowerBound), limits.upperBound)
          }
      
          /// - returns an instance of `Self` clamped to the ``Range``.
          /// - note the value returned will be less than the provided upper bound, as
          ///  is dictated by ``Range``.
          func clamped(to limits: Range<Self>) -> Self {
              return min(max(self, limits.lowerBound), limits.upperBound.nextDown)
          }
      }
      
      extension CGRect {
      
          /// Creates a rectangular sequence of `vertexCount `points denoting a
          /// rectangular path.
          /// - note This is helpful for animating a `Path` composed of `vertexCount`
          /// points into a ``Rectangle``.
          func pointSequence(of vertexCount: Int) -> [CGPoint] {
              // Start at a random corner. When many Polygons are using this
              // animation at once, if they all start at the same corner, an
              // unnatural uniformity of motion emerges.
              var startingPercent = [0, 0.25, 0.5, 0.75].randomElement()!
              var points: [CGPoint] = []
      
              let extraPoints = vertexCount - 4
              let (groups, remainder) = extraPoints
                  .quotientAndRemainder(dividingBy: 3)
      
              for edge in 0...3 {
                  points.append(pointAlongPerimeter(at: startingPercent))
                  for i in (0..<(edge == 3 ? remainder : groups)) {
                      points.append(pointAlongPerimeter(
                          at: startingPercent + 0.25
                          / CGFloat(groups + 1) * CGFloat(i)))
                  }
                  startingPercent += 0.25
                  startingPercent.formTruncatingRemainder(dividingBy: 1)
              }
              assert(points.count == vertexCount)
              return points
          }
      
          /// Returns the ``CGPoint`` that is `percent` along the path of `self`,
          /// with 0% mapping to the top-left corner, progressing clockwise.
          /// E.g. 50% would map to the bottom right corner if and only if `self` is
          ///  a square.
          /// - Parameters:
          ///   - percent: A percentage between `0.0` and `1.0`
          private func pointAlongPerimeter(at percent: CGFloat) -> CGPoint {
              let perimeter = size.width * 2 + size.height * 2
      
              // Mark the four corners as percentages around the rect. For example,
              /// these values for a square would be 25%, 50%, 75%, 100%
              let topRight = size.width / perimeter
              let bottomRight = topRight + (size.height / perimeter)
              let bottomLeft = bottomRight + (size.width / perimeter)
              let topLeft = 1.0
      
              switch percent {
              case 0..<topRight:
                  return CGPoint(
                      x: percent / topRight * size.width,
                      y: minY)
              case topRight..<bottomRight:
                  return CGPoint(
                      x: maxX,
                      y: (percent - topRight)
                      / (bottomRight - topRight) * size.height)
              case bottomRight..<bottomLeft:
                  return CGPoint(
                      x: maxX - ((percent - bottomRight) / (bottomLeft - bottomRight)
                                 * size.width),
                      y: maxY)
              case bottomLeft...topLeft:
                  return CGPoint(
                      x: minX,
                      y: maxY - (percent - bottomLeft) / (topLeft - bottomLeft)
                      * size.height
                  )
              default:
                  preconditionFailure("Invalid percentage requested")
              }
          }
      }
      
      /// Returns a new `CGRect` with the same size as `self`, but centered in `other`
      /// vertically, and horizontally.
      extension CGSize {
          func centered(in other: CGRect) -> CGRect {
              CGRect(x: other.midX - width / 2.0,
                     y: other.midY - height / 2.0,
                     width: width,
                     height: height)
          }
      }
      
      extension Path {
          /// Convenience for initializing a `Path` from an array of `CGPoint`s given
          /// the first point element is the `Path`'s first point.
          init(from points: [CGPoint]) {
              self.init()
              self.addLines(points)
              self.closeSubpath()
          }
      }

Developer Footer

  • Videos
  • WWDC22
  • What's new in SwiftUI
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines