SceneEnvironmentModifier.swift 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. extension Scene {
  2. /// Modifies the scene's environment.
  3. ///
  4. /// - Parameters:
  5. /// - keyPath: The key path to the environment value to update.
  6. /// - newValue: The new value.
  7. public func environment<T>(
  8. _ keyPath: WritableKeyPath<EnvironmentValues, T>,
  9. _ newValue: T
  10. ) -> some Scene {
  11. SceneEnvironmentModifier(self) { environment in
  12. environment.with(keyPath, newValue)
  13. }
  14. }
  15. /// Modifies the scene's environment.
  16. ///
  17. /// - Parameters:
  18. /// - keyPath: The key path to the environment value to update.
  19. /// - transform: A closure that transforms the environment at `keyPath`.
  20. public func transformEnvironment<T>(
  21. _ keyPath: WritableKeyPath<EnvironmentValues, T>,
  22. transform: @escaping (inout T) -> Void
  23. ) -> some Scene {
  24. SceneEnvironmentModifier(self) { environment in
  25. var value = environment[keyPath: keyPath]
  26. transform(&value)
  27. return environment.with(keyPath, value)
  28. }
  29. }
  30. }
  31. struct SceneEnvironmentModifier<Content: Scene>: Scene {
  32. typealias Node = SceneEnvironmentModifierNode<Content>
  33. var content: Content
  34. var modification: (EnvironmentValues) -> EnvironmentValues
  35. init(
  36. _ content: Content,
  37. modification: @escaping (EnvironmentValues) -> EnvironmentValues
  38. ) {
  39. self.content = content
  40. self.modification = modification
  41. }
  42. }
  43. final class SceneEnvironmentModifierNode<Content: Scene>: SceneGraphNode {
  44. typealias NodeScene = SceneEnvironmentModifier<Content>
  45. var modification: (EnvironmentValues) -> EnvironmentValues
  46. var contentNode: Content.Node
  47. init<Backend: BaseAppBackend>(
  48. from scene: NodeScene,
  49. backend: Backend,
  50. environment: EnvironmentValues
  51. ) {
  52. self.modification = scene.modification
  53. self.contentNode = Content.Node(
  54. from: scene.content,
  55. backend: backend,
  56. environment: modification(environment)
  57. )
  58. }
  59. func updateNode(
  60. _ newScene: NodeScene?,
  61. environment: EnvironmentValues
  62. ) -> SceneNodeUpdateResult {
  63. if let newScene {
  64. self.modification = newScene.modification
  65. }
  66. return contentNode.updateNode(
  67. newScene?.content,
  68. environment: modification(environment)
  69. )
  70. }
  71. func update<Backend: BaseAppBackend>(
  72. backend: Backend,
  73. environment: EnvironmentValues
  74. ) {
  75. contentNode.update(
  76. backend: backend,
  77. environment: modification(environment)
  78. )
  79. }
  80. }