Skip to content

Commit ae17991

Browse files
committed
Lower deployment targets to iOS 13, macOS 10.15, watchOS 6 and tvOS 13
1 parent 7bcb230 commit ae17991

File tree

4 files changed

+76
-5
lines changed

4 files changed

+76
-5
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ playground.xcworkspace
4949

5050
.build/
5151

52+
*.xcodeproj

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import PackageDescription
55

66
let package = Package(
77
name: "NumericText",
8-
platforms: [.iOS(.v14), .macOS(.v11), .watchOS(.v7), .tvOS(.v14)],
8+
platforms: [.iOS(.v13), .macOS(.v10_15), .watchOS(.v6), .tvOS(.v13)],
99
products: [
1010
.library(
1111
name: "NumericText",
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import Foundation
2+
import SwiftUI
3+
import Combine
4+
5+
/// See `View.onChange(of: value, perform: action)` for more information
6+
struct ChangeObserver<Base: View, Value: Equatable>: View {
7+
let base: Base
8+
let value: Value
9+
let action: (Value)->Void
10+
11+
let model = Model()
12+
13+
var body: some View {
14+
if model.update(value: value) {
15+
DispatchQueue.main.async { self.action(self.value) }
16+
}
17+
return base
18+
}
19+
20+
class Model {
21+
private var savedValue: Value?
22+
func update(value: Value) -> Bool {
23+
guard value != savedValue else { return false }
24+
savedValue = value
25+
return true
26+
}
27+
}
28+
}
29+
30+
extension View {
31+
/// Adds a modifier for this view that fires an action when a specific value changes.
32+
///
33+
/// You can use `onChange` to trigger a side effect as the result of a value changing, such as an Environment key or a Binding.
34+
///
35+
/// `onChange` is called on the main thread. Avoid performing long-running tasks on the main thread. If you need to perform a long-running task in response to value changing, you should dispatch to a background queue.
36+
///
37+
/// The new value is passed into the closure. The previous value may be captured by the closure to compare it to the new value. For example, in the following code example, PlayerView passes both the old and new values to the model.
38+
///
39+
/// ```
40+
/// struct PlayerView : View {
41+
/// var episode: Episode
42+
/// @State private var playState: PlayState
43+
///
44+
/// var body: some View {
45+
/// VStack {
46+
/// Text(episode.title)
47+
/// Text(episode.showTitle)
48+
/// PlayButton(playState: $playState)
49+
/// }
50+
/// }
51+
/// .onChange(of: playState) { [playState] newState in
52+
/// model.playStateDidChange(from: playState, to: newState)
53+
/// }
54+
/// }
55+
/// ```
56+
///
57+
/// - Parameters:
58+
/// - value: The value to check against when determining whether to run the closure.
59+
/// - action: A closure to run when the value changes.
60+
/// - newValue: The new value that failed the comparison check.
61+
/// - Returns: A modified version of this view
62+
func onChangeShimmed<Value: Equatable>(
63+
of value: Value,
64+
perform action: @escaping (_ newValue: Value)->Void) -> some View {
65+
if #available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) {
66+
return AnyView(self.onChange(of: value, perform: action))
67+
}
68+
return AnyView(ChangeObserver(base: self, value: value, action: action))
69+
}
70+
}

Sources/NumericText/NumericTextModifier.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public struct NumericTextModifier: ViewModifier {
99
@Binding public var text: String
1010
/// A number that will be updated when the `text` is updated.
1111
@Binding public var number: NSNumber?
12-
12+
1313
/// A modifier that observes any changes to a string, and updates that string to remove any non-numeric characters.
1414
/// It also will convert that string to a `NSNumber` for easy use.
1515
///
@@ -24,15 +24,15 @@ public struct NumericTextModifier: ViewModifier {
2424
}
2525

2626
public func body(content: Content) -> some View {
27-
content
28-
.onChange(of: text) { newValue in
27+
return content
28+
.onChangeShimmed(of: text) { newValue in
2929
let numeric = newValue.numericValue(allowDecimalSeparator: isDecimalAllowed)
3030
if newValue != numeric {
3131
text = numeric
3232
}
3333
number = decimalNumberFormatter.number(from: numeric)
3434
}
35-
.onChange(of: number, perform: { newValue in
35+
.onChangeShimmed(of: number, perform: { newValue in
3636
if let number = newValue {
3737
text = decimalNumberFormatter.string(from: number) ?? ""
3838
} else {

0 commit comments

Comments
 (0)