-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: add safe line limit modifier * chore: add safe on change modifier * chore: add safe nav bar hidden modifier * chore: update package version in readme file * fix: on change ios version issue
- Loading branch information
1 parent
98d4881
commit 6baf8f6
Showing
4 changed files
with
200 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
Sources/SwiftSafeUI/Modifiers/Auxiliary View/SafeNavBarHidden.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// | ||
// SafeAutocapitalization.swift | ||
// | ||
// GitHub Repo and Documentation: /~https://github.com/BaherTamer/SwiftSafeUI | ||
// | ||
// Copyright © 2024 Baher Tamer. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
extension View { | ||
/// | ||
/// Config navigation bar visibility based on the provided `Bool` value. Handles deprecation logic for different iOS versions. | ||
/// | ||
/// If the device is running iOS 18.0 or later, | ||
/// it uses the new [``toolbarVisibility(_:for:)``](https://developer.apple.com/documentation/swiftui/view/toolbarvisibility(_:for:)) modifier. | ||
/// If the device is running iOS 16.0 or later, | ||
/// it uses the new [``toolbar(_:for:)``](https://developer.apple.com/documentation/swiftui/view/toolbar(_:for:)) modifier. | ||
/// For earlier versions, it falls back to the old [``navigationBarHidden(_:)``](https://developer.apple.com/documentation/swiftui/view/navigationbarhidden(_:)) modifier. | ||
/// | ||
/// - Parameters: | ||
/// - isHidden: A `Bool` value that determines whether the navigation bar should be hidden or not. | ||
/// | ||
/// - Returns: A `View` that reflects the visibility state of the navigation bar. | ||
/// | ||
public func safeNavBarHidden(_ isHidden: Bool) -> some View { | ||
modifier( | ||
SafeNavBarHidden(isHidden: isHidden) | ||
) | ||
} | ||
} | ||
|
||
fileprivate struct SafeNavBarHidden: ViewModifier { | ||
// MARK: - Inputs | ||
let isHidden: Bool | ||
|
||
// MARK: - Body | ||
func body(content: Content) -> some View { | ||
if #available(iOS 18.0, *) { | ||
content | ||
.toolbarVisibility( | ||
isHidden ? .hidden : .automatic, | ||
for: .navigationBar | ||
) | ||
} else if #available(iOS 16.0, *) { | ||
content | ||
.toolbar( | ||
isHidden ? .hidden : .automatic, | ||
for: .navigationBar | ||
) | ||
} else { | ||
content | ||
.navigationBarHidden(isHidden) | ||
} | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
Sources/SwiftSafeUI/Modifiers/Input & Event/SafeOnChange.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// | ||
// SafeAutocapitalization.swift | ||
// | ||
// GitHub Repo and Documentation: /~https://github.com/BaherTamer/SwiftSafeUI | ||
// | ||
// Copyright © 2024 Baher Tamer. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
@available(iOS 14.0, *) | ||
extension View { | ||
/// | ||
/// Adds an action to perform when the given value changes. Handles deprecation logic for different iOS versions. | ||
/// | ||
/// This modifier triggers an action when the specified value changes. | ||
/// It ensures compatibility with different iOS versions by using the appropriate `onChange` modifier based on the iOS version. | ||
/// | ||
/// If the device is running iOS 17.0 or later, | ||
/// it uses the new [``onChange(of:initial:_:)``](https://developer.apple.com/documentation/swiftui/view/onchange(of:initial:_:)-4psgg) modifier. | ||
/// For earlier versions, it falls back to the old [``onChange(of:perform:)``](https://developer.apple.com/documentation/swiftui/view/onchange(of:perform:)) modifier. | ||
/// | ||
/// > Note: This modifier is available from iOS 14.0 or later. | ||
/// | ||
/// - Parameters: | ||
/// - value: The value to monitor for changes. | ||
/// - action: A closure that is called with the old and new values when a change is detected. | ||
/// | ||
/// - Returns: A view that applies the specified action when the value changes. | ||
/// | ||
public func safeOnChange<Value: Equatable>( | ||
_ value: Value, | ||
perform action: @escaping (Value, Value) -> Void | ||
) -> some View { | ||
modifier( | ||
SafeOnChange( | ||
value: value, | ||
action: action | ||
) | ||
) | ||
} | ||
} | ||
|
||
@available(iOS 14.0, *) | ||
fileprivate struct SafeOnChange<Value: Equatable>: ViewModifier { | ||
let value: Value | ||
var action: (Value, Value) -> Void | ||
|
||
func body(content: Content) -> some View { | ||
if #available(iOS 17.0, *) { | ||
content | ||
.onChange(of: value, action) | ||
} else { | ||
content | ||
.onChange(of: value) { [value] newValue in | ||
action(value, newValue) | ||
} | ||
} | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
Sources/SwiftSafeUI/Modifiers/Text & Symbol/SafeLineLimit.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// | ||
// SafeAutocapitalization.swift | ||
// | ||
// GitHub Repo and Documentation: /~https://github.com/BaherTamer/SwiftSafeUI | ||
// | ||
// Copyright © 2024 Baher Tamer. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
extension View { | ||
/// | ||
/// Applies a line limit to the current view, handling the logic for reserving space for different iOS versions. | ||
/// | ||
/// This modifier applies the line limit and reserves space using the appropriate method based on the iOS version. | ||
/// | ||
/// If the device is running iOS 16.0 or later, | ||
/// it uses the [``lineLimit(_:reservesSpace:)``](https://developer.apple.com/documentation/swiftui/view/linelimit(_:reservesspace:)) modifier. | ||
/// For earlier versions, it sets a fixed frame height to reserve space for the specified number of lines. | ||
/// | ||
/// - Parameters: | ||
/// - limit: The maximum number of lines for the text view. | ||
/// - reservesSpace: A Boolean value indicating whether the view reserves space for the specified number of lines, even if fewer lines are displayed. | ||
/// | ||
public func safeLineLimit( | ||
_ limit: Int, | ||
reservesSpace: Bool | ||
) -> some View { | ||
modifier( | ||
SafeLineLimit( | ||
limit: limit, | ||
reservesSpace: reservesSpace | ||
) | ||
) | ||
} | ||
} | ||
|
||
fileprivate struct SafeLineLimit: ViewModifier { | ||
// MARK: - Inputs | ||
let limit: Int | ||
let reservesSpace: Bool | ||
|
||
// MARK: - Variables | ||
@State private var height: CGFloat = TextHeightPreferenceKey.defaultValue | ||
|
||
// MARK: - Body | ||
func body(content: Content) -> some View { | ||
if #available(iOS 16.0, *) { | ||
content | ||
.lineLimit(limit, reservesSpace: reservesSpace) | ||
} else { | ||
content | ||
.lineLimit(limit) | ||
.background(geometryReader) | ||
.frame(height: reservesSpace ? height : nil, alignment: .top) | ||
.onPreferenceChange(TextHeightPreferenceKey.self) { height in | ||
self.height = height * CGFloat(limit) | ||
} | ||
} | ||
} | ||
|
||
// MARK: - Private Helpers | ||
private var geometryReader: some View { | ||
GeometryReader { geometry in | ||
Color.clear | ||
.preference( | ||
key: TextHeightPreferenceKey.self, | ||
value: geometry.size.height | ||
) | ||
} | ||
} | ||
} | ||
|
||
private struct TextHeightPreferenceKey: PreferenceKey { | ||
// MARK: - Variables | ||
static var defaultValue: CGFloat = 20 | ||
|
||
// MARK: - Config Functions | ||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { | ||
value = max(value, nextValue()) | ||
} | ||
} | ||
|