mirror of
https://github.com/laosb/TypedAppStorage.git
synced 2025-06-23 09:41:08 +00:00
chore: format with swift format
This commit is contained in:
parent
23ffb4892b
commit
4c932cb336
3 changed files with 45 additions and 30 deletions
|
@ -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"]
|
||||
),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue