chore: format with swift format

This commit is contained in:
Shibo Lyu 2025-06-14 19:55:53 +08:00
parent 23ffb4892b
commit 4c932cb336
3 changed files with 45 additions and 30 deletions

View file

@ -10,21 +10,24 @@ let package = Package(
.macOS(.v11),
.macCatalyst(.v14),
.tvOS(.v14),
.watchOS(.v7)
.watchOS(.v7),
],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "TypedAppStorage",
targets: ["TypedAppStorage"]),
targets: ["TypedAppStorage"]
)
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "TypedAppStorage"),
name: "TypedAppStorage"
),
.testTarget(
name: "TypedAppStorageTests",
dependencies: ["TypedAppStorage"]),
dependencies: ["TypedAppStorage"]
),
]
)

View file

@ -18,28 +18,36 @@ public protocol TypedAppStorageValue: Codable {
public struct TypedAppStorage<Value: TypedAppStorageValue>: DynamicProperty {
private var appStorage: AppStorage<String>
private var initialValue: Value
/// Store and fetch value from the defined store, with a predefined default value.
///
/// This default value if defined is preferred over ``TypedAppStorageValue/defaultValue``.
public init(wrappedValue: Value, store: UserDefaults? = nil) {
initialValue = wrappedValue
let initialData = try? JSONEncoder().encode(wrappedValue)
let initialString = (initialData == nil ? nil : String(data: initialData!, encoding: .utf8)) ?? ""
appStorage = .init(wrappedValue: initialString, Value.appStorageKey, store: store)
let initialString =
(initialData == nil ? nil : String(data: initialData!, encoding: .utf8))
?? ""
appStorage = .init(
wrappedValue: initialString,
Value.appStorageKey,
store: store
)
}
/// Store and fetch value from the defined store.
///
/// ``TypedAppStorageValue/defaultValue`` is used if no value was previously saved.
public init(store: UserDefaults? = nil) {
self.init(wrappedValue: Value.defaultValue, store: store)
}
/// The wrapped ``TypedAppStorageValue``.
public var wrappedValue: Value {
get {
guard let data = appStorage.wrappedValue.data(using: .utf8) else { return initialValue }
guard let data = appStorage.wrappedValue.data(using: .utf8) else {
return initialValue
}
return (try? JSONDecoder().decode(Value.self, from: data)) ?? initialValue
}
nonmutating set {
@ -50,7 +58,7 @@ public struct TypedAppStorage<Value: TypedAppStorageValue>: DynamicProperty {
appStorage.wrappedValue = newString
}
}
/// A two-way binding of ``wrappedValue``.
public var projectedValue: Binding<Value> {
.init {

View file

@ -1,5 +1,6 @@
import XCTest
import SwiftUI
import XCTest
@testable import TypedAppStorage
struct PreferredFruit: TypedAppStorageValue, Equatable {
@ -9,13 +10,13 @@ struct PreferredFruit: TypedAppStorageValue, Equatable {
enum Freshness: Codable {
case veryFresh, moderate, somewhatStale
}
static var appStorageKey = "preferredFruit"
static var defaultValue = PreferredFruit(.veryFresh, .apple)
var fruit: Fruit
var freshness: Freshness
init(_ freshness: Freshness, _ fruit: Fruit) {
self.fruit = fruit
self.freshness = freshness
@ -24,11 +25,11 @@ struct PreferredFruit: TypedAppStorageValue, Equatable {
struct TestArticle: View {
@TypedAppStorage var preferredFruit: PreferredFruit
func changePreferred(to newValue: PreferredFruit) {
preferredFruit = newValue
}
var body: some View {
Text("Test")
}
@ -36,11 +37,11 @@ struct TestArticle: View {
struct TestArticleWithADifferentDefault: View {
@TypedAppStorage var preferredFruit: PreferredFruit = .init(.moderate, .pear)
func changePreferred(to newValue: PreferredFruit) {
preferredFruit = newValue
}
var body: some View {
Text("Test")
}
@ -50,33 +51,36 @@ final class TypedAppStorageTests: XCTestCase {
override func setUp() {
UserDefaults.standard.removeObject(forKey: "preferredFruit")
}
func testReadDefaultValue() throws {
let testArticle = TestArticle()
XCTAssertEqual(testArticle.preferredFruit, PreferredFruit(.veryFresh, .apple))
XCTAssertEqual(
testArticle.preferredFruit,
PreferredFruit(.veryFresh, .apple)
)
}
func testCallSiteDefault() throws {
let testArticle = TestArticleWithADifferentDefault()
XCTAssertEqual(testArticle.preferredFruit, .init(.moderate, .pear))
}
func testSaveAndReadBack() throws {
let testArticle = TestArticle()
testArticle.changePreferred(to: .init(.somewhatStale, .banana))
XCTAssertEqual(testArticle.preferredFruit, .init(.somewhatStale, .banana))
}
func testSaveAndReadElsewhere() throws {
let articleA = TestArticle()
let articleB = TestArticle()
articleA.changePreferred(to: .init(.moderate, .banana))
XCTAssertEqual(articleB.preferredFruit, .init(.moderate, .banana))
}
}