From 5c4f154172cee5e55cbba2abbd6b2bed3d850432 Mon Sep 17 00:00:00 2001 From: Daniel Saidi Date: Mon, 22 Apr 2024 10:01:27 +0200 Subject: [PATCH] Make contexts inject themselves as environment object --- RELEASE_NOTES.md | 11 ++++++++ .../SwiftUIKit/Extensions/View+Label.swift | 20 +++++++++++++- .../SwiftUIKit/Gestures/GestureButton.swift | 2 +- .../Gestures/ScrollViewGestureButton.swift | 13 +++------- .../SwiftUIKit/Lists/ListButtonStyle.swift | 26 +++++++------------ .../Presentation/AlertContext.swift | 9 ++++--- .../Presentation/FullScreenCoverContext.swift | 12 ++++++--- .../Presentation/SheetContext.swift | 8 ++++-- 8 files changed, 66 insertions(+), 35 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 313e5c6b29..cce9276c7f 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,6 +4,17 @@ SwiftUIKit makes its best effort to honor semver, but breaking changes can occur +## 4.2.1 + +### 💡 Behavior changes + +* `View.alert` now injects the context as environment object. +* `View.label` now takes a localized string key instead of a key. +* `View.sheet` now injects the context as environment object. +* `View.fullScreenCover` now injects the context as environment object. + + + ## 4.2 This version refactors many views to take their styles & configs as environment values, instead of injecting them in the initializer. diff --git a/Sources/SwiftUIKit/Extensions/View+Label.swift b/Sources/SwiftUIKit/Extensions/View+Label.swift index 5e6e63c20e..7ca6573354 100644 --- a/Sources/SwiftUIKit/Extensions/View+Label.swift +++ b/Sources/SwiftUIKit/Extensions/View+Label.swift @@ -14,13 +14,31 @@ public extension View { /// /// - Parameters: /// - text: The label text. - func label(_ text: String) -> some View { + func label( + _ text: LocalizedStringKey, + bundle: Bundle? = nil + ) -> some View { Label { Text(text) } icon: { self } } + + /// Convert the view to a localized label. + /// + /// - Parameters: + /// - text: The label text. + func localizedLabel( + _ text: LocalizedStringKey, + bundle: Bundle? = nil + ) -> some View { + Label { + Text(text, bundle: bundle) + } icon: { + self + } + } } #Preview { diff --git a/Sources/SwiftUIKit/Gestures/GestureButton.swift b/Sources/SwiftUIKit/Gestures/GestureButton.swift index ea87dab3fc..8b0f3fe3ed 100644 --- a/Sources/SwiftUIKit/Gestures/GestureButton.swift +++ b/Sources/SwiftUIKit/Gestures/GestureButton.swift @@ -11,7 +11,7 @@ import SwiftUI /** This button supports triggering different gestures in a way - that maximized performance. + that maximizes performance. This button can't be used in a `ScrollView` since it blocks the scroll view gesture. To implement multi-gesture support diff --git a/Sources/SwiftUIKit/Gestures/ScrollViewGestureButton.swift b/Sources/SwiftUIKit/Gestures/ScrollViewGestureButton.swift index f03131757a..2f43d7ae67 100644 --- a/Sources/SwiftUIKit/Gestures/ScrollViewGestureButton.swift +++ b/Sources/SwiftUIKit/Gestures/ScrollViewGestureButton.swift @@ -13,17 +13,12 @@ import SwiftUI This button supports triggering different gestures in a way that works within a `ScrollView`. - This button can't be used in a `ScrollView` since it blocks - the scroll view gesture. To implement multi-gesture support - in a `ScrollView`, use a ``ScrollViewGestureButton``. - - This button can be used in a `ScrollView` and doesn't block - the scroll view gesture despite applying many gestures. The - complicated code is the result of much trial and error, and - has been tested to not affect the scrolling or any gestures. + This button does npt block scroll view gesture. The code is + the result of much trial & error and has been tested to not + affect scrolling. If you don't need to use a scroll view, you should consider - using a ``GestureButton`` instead. + using a ``GestureButton`` instead.- Note that the view uses an underlying `ButtonStyle` to make gestures work. It can thus not apply another style, but you diff --git a/Sources/SwiftUIKit/Lists/ListButtonStyle.swift b/Sources/SwiftUIKit/Lists/ListButtonStyle.swift index 0aa311b7e0..4cc6ba6229 100644 --- a/Sources/SwiftUIKit/Lists/ListButtonStyle.swift +++ b/Sources/SwiftUIKit/Lists/ListButtonStyle.swift @@ -8,13 +8,11 @@ import SwiftUI -/** - This style makes buttons take up the entire row and applies - a content shape that makes the entire view tappable. - - You can apply the style with `.buttonStyle(.list)`, and can - apply it to an entire list, just as with other styles. - */ +/// This style makes the button take up the entire row, then +/// applies a shape that makes the entire view tappable. +/// +/// You can apply this style with `.buttonStyle(.list)`, and +/// can apply it to an entire list, like any other style. public struct ListButtonStyle: ButtonStyle { /// Create a custom style. @@ -61,9 +59,11 @@ public extension ButtonStyle where Self == ListButtonStyle { var body: some View { List { - ForEach(0...100, id: \.self) { - button("Button \($0)") - .buttonStyle($0 == 0 ? .list : .list(pressedOpacity: 0.1)) + ForEach(0...100, id: \.self) { index in + Button("Button \(index)") { + overlayText = "\(index) tapped!" + } + .buttonStyle(index == 0 ? .list : .list(pressedOpacity: 0.1)) } } .overlay(overlay) @@ -78,12 +78,6 @@ public extension ButtonStyle where Self == ListButtonStyle { .opacity(overlayText.isEmpty ? 0 : 1) .onTapGesture { overlayText = "" } } - - func button(_ name: String) -> some View { - Button(name) { - overlayText = "\(name) tapped!" - } - } } return Preview() diff --git a/Sources/SwiftUIKit/Presentation/AlertContext.swift b/Sources/SwiftUIKit/Presentation/AlertContext.swift index 8060dd2091..f4cb825004 100644 --- a/Sources/SwiftUIKit/Presentation/AlertContext.swift +++ b/Sources/SwiftUIKit/Presentation/AlertContext.swift @@ -35,10 +35,10 @@ import SwiftUI In the code above, we create a custom, static `Alert` value to easily let us share and reuse alerts in an app or domain. - You can also use enums to define multiple alerts. - You can also setup a global context in the application root, - and pass it as an environment object, to get a single value. + This view modifier will also inject the provided context as + an environment object into the view hierarchy, to let other + views in the same view hierarchy reuse the same context. */ public class AlertContext: PresentationContext { @@ -52,10 +52,13 @@ public class AlertContext: PresentationContext { public extension View { /// Bind an ``AlertContext`` to the view. + /// + /// This also injects this context as environment object. func alert(_ context: AlertContext) -> some View { alert( isPresented: context.isActiveBinding, content: context.content ?? { Alert(title: Text("")) } ) + .environmentObject(context) } } diff --git a/Sources/SwiftUIKit/Presentation/FullScreenCoverContext.swift b/Sources/SwiftUIKit/Presentation/FullScreenCoverContext.swift index fb27e7aaa8..5b5fe20873 100644 --- a/Sources/SwiftUIKit/Presentation/FullScreenCoverContext.swift +++ b/Sources/SwiftUIKit/Presentation/FullScreenCoverContext.swift @@ -28,8 +28,9 @@ import SwiftUI } ``` - You can also setup a global context in the application root, - and pass it as an environment object, to get a single value. + This view modifier will also inject the provided context as + an environment object into the view hierarchy, to let other + views in the same view hierarchy reuse the same context. */ public class FullScreenCoverContext: PresentationContext { @@ -46,11 +47,16 @@ import SwiftUI public extension View { /// Bind an ``FullScreenCoverContext`` to the view. - func fullScreenCover(_ context: FullScreenCoverContext) -> some View { + /// + /// This also injects this context as environment object. + func fullScreenCover( + _ context: FullScreenCoverContext + ) -> some View { fullScreenCover( isPresented: context.isActiveBinding, content: context.content ?? EmptyView().any ) + .environmentObject(context) } } #endif diff --git a/Sources/SwiftUIKit/Presentation/SheetContext.swift b/Sources/SwiftUIKit/Presentation/SheetContext.swift index 09296cf883..b48a0e7271 100644 --- a/Sources/SwiftUIKit/Presentation/SheetContext.swift +++ b/Sources/SwiftUIKit/Presentation/SheetContext.swift @@ -28,8 +28,9 @@ import SwiftUI } ``` - You can also setup a global context in the application root, - and pass it as an environment object, to get a single value. + This view modifier will also inject the provided context as + an environment object into the view hierarchy, to let other + views in the same view hierarchy reuse the same context. */ public class SheetContext: PresentationContext { @@ -41,10 +42,13 @@ public class SheetContext: PresentationContext { public extension View { /// Bind an ``SheetContext`` to the view. + /// + /// This also injects this context as environment object. func sheet(_ context: SheetContext) -> some View { sheet( isPresented: context.isActiveBinding, content: context.content ?? EmptyView().any ) + .environmentObject(context) } }