diff --git a/Sources/SkeletonUI/Extensions/Image+OptionalType.swift b/Sources/SkeletonUI/Extensions/Image+OptionalType.swift deleted file mode 100644 index 3b4f4e5..0000000 --- a/Sources/SkeletonUI/Extensions/Image+OptionalType.swift +++ /dev/null @@ -1,102 +0,0 @@ -import SwiftUI - -public extension Image { - #if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) - init(uiImage: UIImage?) { - if let uiImage = uiImage { - self.init(uiImage: uiImage) - } else { - self.init(uiImage: UIImage()) - } - } - - #elseif os(macOS) - init(nsImage: NSImage?) { - if let nsImage = nsImage { - self.init(nsImage: nsImage) - } else { - self.init(nsImage: NSImage()) - } - } - #endif - - init(_ name: String?, bundle: Bundle? = nil) { - if let name = name { - self.init(name, bundle: bundle) - } else { - self.init(String(), bundle: bundle) - } - } - - init(_ name: String?, bundle: Bundle? = nil, label: Text) { - if let name = name { - self.init(name, bundle: bundle, label: label) - } else { - self.init(String(), bundle: bundle, label: label) - } - } - - init(decorative name: String?, bundle: Bundle? = nil) { - if let name = name { - self.init(decorative: name, bundle: bundle) - } else { - self.init(decorative: String(), bundle: bundle) - } - } - - #if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) - init(systemName: String?) { - if let systemName = systemName { - self.init(systemName: systemName) - } else { - self.init(systemName: String()) - } - } - #endif - - #if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) - init(_ cgImage: CGImage?, scale: CGFloat, orientation: Image.Orientation = .up, label: Text) { - if let cgImage = cgImage { - self.init(cgImage, scale: scale, orientation: orientation, label: label) - } else if let image = UIImage().cgImage { - self.init(image, scale: scale, orientation: orientation, label: label) - } else { - self.init(String()) - } - } - - #elseif os(macOS) - init(_ cgImage: CGImage?, scale: CGFloat, orientation: Image.Orientation = .up, label: Text) { - if let cgImage = cgImage { - self.init(cgImage, scale: scale, orientation: orientation, label: label) - } else if let image = NSImage().cgImage(forProposedRect: nil, context: nil, hints: nil) { - self.init(image, scale: scale, orientation: orientation, label: label) - } else { - self.init(String()) - } - } - #endif - - #if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) - init(decorative cgImage: CGImage?, scale: CGFloat, orientation: Image.Orientation = .up) { - if let cgImage = cgImage { - self.init(decorative: cgImage, scale: scale, orientation: orientation) - } else if let image = UIImage().cgImage { - self.init(decorative: image, scale: scale, orientation: orientation) - } else { - self.init(String()) - } - } - - #elseif os(macOS) - init(decorative cgImage: CGImage?, scale: CGFloat, orientation: Image.Orientation = .up) { - if let cgImage = cgImage { - self.init(decorative: cgImage, scale: scale, orientation: orientation) - } else if let image = NSImage().cgImage(forProposedRect: nil, context: nil, hints: nil) { - self.init(decorative: image, scale: scale, orientation: orientation) - } else { - self.init(String()) - } - } - #endif -} diff --git a/Sources/SkeletonUI/Extensions/Optional+OptionalType.swift b/Sources/SkeletonUI/Extensions/Optional+OptionalType.swift deleted file mode 100644 index dba2a5e..0000000 --- a/Sources/SkeletonUI/Extensions/Optional+OptionalType.swift +++ /dev/null @@ -1,5 +0,0 @@ -extension Optional: OptionalType { - public var wrapped: Wrapped? { - self - } -} diff --git a/Sources/SkeletonUI/Extensions/SecureField+OptionalType.swift b/Sources/SkeletonUI/Extensions/SecureField+OptionalType.swift deleted file mode 100644 index ca29b1b..0000000 --- a/Sources/SkeletonUI/Extensions/SecureField+OptionalType.swift +++ /dev/null @@ -1,19 +0,0 @@ -import SwiftUI - -public extension SecureField where Label == Text { - init(_ titleKey: LocalizedStringKey?, text: Binding, onCommit: @escaping () -> Void = {}) { - if let titleKey = titleKey { - self.init(titleKey, text: text, onCommit: onCommit) - } else { - self.init(LocalizedStringKey(String()), text: text, onCommit: onCommit) - } - } - - init(_ title: S?, text: Binding, onCommit: @escaping () -> Void = {}) where S: OptionalType, S.Wrapped: StringProtocol { - if let title = title?.wrapped { - self.init(title, text: text, onCommit: onCommit) - } else { - self.init(String(), text: text, onCommit: onCommit) - } - } -} diff --git a/Sources/SkeletonUI/Extensions/Text+OptionalType.swift b/Sources/SkeletonUI/Extensions/Text+OptionalType.swift deleted file mode 100644 index 7f12d97..0000000 --- a/Sources/SkeletonUI/Extensions/Text+OptionalType.swift +++ /dev/null @@ -1,27 +0,0 @@ -import SwiftUI - -public extension Text { - init(_ content: S?) where S: OptionalType, S.Wrapped: StringProtocol { - if let content = content?.wrapped { - self.init(content) - } else { - self.init(String()) - } - } - - init(_ key: LocalizedStringKey?, tableName: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil) { - if let key = key { - self.init(key, tableName: tableName, bundle: bundle, comment: comment) - } else { - self.init(LocalizedStringKey(String()), tableName: tableName, bundle: bundle, comment: comment) - } - } - - init(verbatim content: String?) { - if let content = content { - self.init(verbatim: content) - } else { - self.init(verbatim: String()) - } - } -} diff --git a/Sources/SkeletonUI/Extensions/TextField+OptionalType.swift b/Sources/SkeletonUI/Extensions/TextField+OptionalType.swift deleted file mode 100644 index 00e945d..0000000 --- a/Sources/SkeletonUI/Extensions/TextField+OptionalType.swift +++ /dev/null @@ -1,35 +0,0 @@ -import SwiftUI - -public extension TextField where Label == Text { - init(titleKey: LocalizedStringKey?, text: Binding, onEditingChanged: @escaping (Bool) -> Void = { _ in }, onCommit: @escaping () -> Void = {}) { - if let titleKey = titleKey { - self.init(titleKey, text: text, onEditingChanged: onEditingChanged, onCommit: onCommit) - } else { - self.init(LocalizedStringKey(String()), text: text, onEditingChanged: onEditingChanged, onCommit: onCommit) - } - } - - init(_ title: S?, text: Binding, onEditingChanged: @escaping (Bool) -> Void = { _ in }, onCommit: @escaping () -> Void = {}) where S: OptionalType, S.Wrapped: StringProtocol { - if let title = title?.wrapped { - self.init(title, text: text, onEditingChanged: onEditingChanged, onCommit: onCommit) - } else { - self.init(String(), text: text, onEditingChanged: onEditingChanged, onCommit: onCommit) - } - } - - init(titleKey: LocalizedStringKey?, value: Binding, formatter: Formatter, onEditingChanged: @escaping (Bool) -> Void = { _ in }, onCommit: @escaping () -> Void = {}) { - if let titleKey = titleKey { - self.init(titleKey, value: value, formatter: formatter, onEditingChanged: onEditingChanged, onCommit: onCommit) - } else { - self.init(LocalizedStringKey(String()), value: value, formatter: formatter, onEditingChanged: onEditingChanged, onCommit: onCommit) - } - } - - init(_ title: S?, value: Binding, formatter: Formatter, onEditingChanged: @escaping (Bool) -> Void = { _ in }, onCommit: @escaping () -> Void = {}) where S: OptionalType, S.Wrapped: StringProtocol { - if let title = title?.wrapped { - self.init(title, value: value, formatter: formatter, onEditingChanged: onEditingChanged, onCommit: onCommit) - } else { - self.init(String(), value: value, formatter: formatter, onEditingChanged: onEditingChanged, onCommit: onCommit) - } - } -} diff --git a/Sources/SkeletonUI/Extensions/Toggle+OptionalType.swift b/Sources/SkeletonUI/Extensions/Toggle+OptionalType.swift deleted file mode 100644 index 78ee3fa..0000000 --- a/Sources/SkeletonUI/Extensions/Toggle+OptionalType.swift +++ /dev/null @@ -1,29 +0,0 @@ -import SwiftUI - -public extension Toggle where Label: View { - init(isOn: Binding?, @ViewBuilder label: () -> Label) { - if let isOn = isOn { - self.init(isOn: isOn, label: label) - } else { - self.init(isOn: Binding.constant(Bool()), label: label) - } - } -} - -public extension Toggle where Label == Text { - init(_ titleKey: LocalizedStringKey?, isOn: Binding) { - if let titleKey = titleKey { - self.init(titleKey, isOn: isOn) - } else { - self.init(String(), isOn: isOn) - } - } - - init(_ title: S?, isOn: Binding) where S: OptionalType, S.Wrapped: StringProtocol { - if let title = title?.wrapped { - self.init(title, isOn: isOn) - } else { - self.init(String(), isOn: isOn) - } - } -} diff --git a/Sources/SkeletonUI/Protocols/OptionalType.swift b/Sources/SkeletonUI/Protocols/OptionalType.swift deleted file mode 100644 index f1cb7cb..0000000 --- a/Sources/SkeletonUI/Protocols/OptionalType.swift +++ /dev/null @@ -1,4 +0,0 @@ -public protocol OptionalType { - associatedtype Wrapped - var wrapped: Wrapped? { get } -} diff --git a/Sources/SkeletonUI/Skeleton/SkeletonForEach.swift b/Sources/SkeletonUI/Skeleton/SkeletonForEach.swift index 7e5d3d8..312be01 100644 --- a/Sources/SkeletonUI/Skeleton/SkeletonForEach.swift +++ b/Sources/SkeletonUI/Skeleton/SkeletonForEach.swift @@ -1,7 +1,7 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) -public struct SkeletonForEach: View where Data: RandomAccessCollection, Data.Element: Identifiable, Content: View { +public struct SkeletonForEach: View where Data: RandomAccessCollection, Data.Element: Hashable, Content: View { private let data: Data private let quantity: Int private let content: (Bool, Data.Element?) -> Content diff --git a/Sources/SkeletonUI/Skeleton/SkeletonList.swift b/Sources/SkeletonUI/Skeleton/SkeletonList.swift index 1d5eeed..5f46bca 100644 --- a/Sources/SkeletonUI/Skeleton/SkeletonList.swift +++ b/Sources/SkeletonUI/Skeleton/SkeletonList.swift @@ -1,7 +1,7 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) -public struct SkeletonList: View where Data: RandomAccessCollection, Data.Element: Identifiable, Content: View { +public struct SkeletonList: View where Data: RandomAccessCollection, Data.Element: Hashable, Content: View { private let data: Data private let quantity: Int private let content: (Bool, Data.Element?) -> Content diff --git a/Tests/SkeletonUISnapshotTests/SnapshotTests.swift b/Tests/SkeletonUISnapshotTests/SnapshotTests.swift index 4d2f7a9..69ea1db 100644 --- a/Tests/SkeletonUISnapshotTests/SnapshotTests.swift +++ b/Tests/SkeletonUISnapshotTests/SnapshotTests.swift @@ -3,40 +3,35 @@ import SnapshotTesting import SwiftUI import XCTest -extension String: Identifiable { - public var id: UUID { - UUID() - } -} - final class SnapshotTests: XCTestCase { func testDefaultText() { - let one = Text(nil).skeleton(with: true) - let two = Text(verbatim: nil).skeleton(with: true) + let one = Text("").skeleton(with: true) + let two = Text("").skeleton(with: true) assertNamedSnapshot(matching: one, as: .image(size: CGSize(width: 100, height: 50))) assertNamedSnapshot(matching: two, as: .image(size: CGSize(width: 100, height: 50))) } func testCustomText() { - let view = Text(nil).skeleton(with: true, animation: .pulse(), appearance: .solid(), shape: .rectangle, lines: 2, scales: [1: 0.5]) + let view = Text("").skeleton(with: true, animation: .pulse(), appearance: .solid(), shape: .rectangle, lines: 2, scales: [1: 0.5]) assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 50))) } func testCustomSize() { let size = CGSize(width: 100, height: 100) - let view = Text(nil).skeleton(with: true, size: size) + let view = Text("").skeleton(with: true, size: size) assertNamedSnapshot(matching: view, as: .image(size: size)) } func testDefaultImage() { #if os(macOS) - let one = Image(nsImage: nil).skeleton(with: true) + let one = Image(nsImage: NSImage()).skeleton(with: true) #else - let one = Image(uiImage: nil).skeleton(with: true) + let one = Image(uiImage: UIImage()).skeleton(with: true) #endif - let two = Image(nil, scale: .zero, label: Text(String())).skeleton(with: true) - let three = Image(nil).skeleton(with: true) - let four = Image(nil, label: Text(String())).skeleton(with: true) + let two = NSImage().cgImage(forProposedRect: nil, context: nil, hints: nil).map { Image($0, scale: .zero, label: Text("")) } + .skeleton(with: true) + let three = Image("").skeleton(with: true) + let four = Image("", label: Text(String())).skeleton(with: true) assertNamedSnapshot(matching: one, as: .image(size: CGSize(width: 100, height: 100))) assertNamedSnapshot(matching: two, as: .image(size: CGSize(width: 100, height: 100))) assertNamedSnapshot(matching: three, as: .image(size: CGSize(width: 100, height: 100))) @@ -45,13 +40,14 @@ final class SnapshotTests: XCTestCase { func testCustomImage() { #if os(macOS) - let one = Image(nsImage: nil).skeleton(with: true, animation: .none, shape: .circle) + let one = Image("").skeleton(with: true, animation: .none, shape: .circle) #else - let one = Image(uiImage: nil).skeleton(with: true, animation: .none, shape: .circle) + let one = Image(optional: nil).skeleton(with: true, animation: .none, shape: .circle) #endif - let two = Image(nil, scale: .zero, label: Text(String())).skeleton(with: true, animation: .none, shape: .circle) - let three = Image(nil).skeleton(with: true, animation: .none, shape: .circle) - let four = Image(nil, label: Text(String())).skeleton(with: true, animation: .none, shape: .circle) + let two = NSImage().cgImage(forProposedRect: nil, context: nil, hints: nil).map { Image($0, scale: .zero, label: Text("")) } + .skeleton(with: true, animation: .none, shape: .circle) + let three = Image("").skeleton(with: true, animation: .none, shape: .circle) + let four = Image("", label: Text(String())).skeleton(with: true, animation: .none, shape: .circle) assertNamedSnapshot(matching: one, as: .image(size: CGSize(width: 100, height: 100))) assertNamedSnapshot(matching: two, as: .image(size: CGSize(width: 100, height: 100))) assertNamedSnapshot(matching: three, as: .image(size: CGSize(width: 100, height: 100))) @@ -60,7 +56,7 @@ final class SnapshotTests: XCTestCase { func testSystemImage() { #if os(macOS) - let one = Image(nil).skeleton(with: true) + let one = Image("").skeleton(with: true) let two = Image("checkmark").skeleton(with: true, animation: .none, shape: .circle) #else let one = Image(systemName: nil).skeleton(with: true) @@ -71,67 +67,67 @@ final class SnapshotTests: XCTestCase { } func testDefaultTextField() { - let one = TextField(titleKey: nil, text: Binding.constant(String())).skeleton(with: true) - let two = TextField(titleKey: nil, value: Binding.constant(String()), formatter: NumberFormatter()).skeleton(with: true) + let one = TextField("", text: Binding.constant(String())).skeleton(with: true) + let two = TextField("", value: Binding.constant(String()), formatter: NumberFormatter()).skeleton(with: true) assertNamedSnapshot(matching: one, as: .image(size: CGSize(width: 100, height: 50))) assertNamedSnapshot(matching: two, as: .image(size: CGSize(width: 100, height: 50))) } func testCustomTextField() { - let one = TextField(titleKey: nil, text: Binding.constant(String())).skeleton(with: true, appearance: .gradient(.angular), shape: .ellipse) - let two = TextField(titleKey: nil, value: Binding.constant(String()), formatter: NumberFormatter()).skeleton(with: true, appearance: .gradient(.angular), shape: .ellipse) + let one = TextField("", text: Binding.constant(String())).skeleton(with: true, appearance: .gradient(.angular), shape: .ellipse) + let two = TextField("", value: Binding.constant(String()), formatter: NumberFormatter()).skeleton(with: true, appearance: .gradient(.angular), shape: .ellipse) assertNamedSnapshot(matching: one, as: .image(size: CGSize(width: 100, height: 50))) assertNamedSnapshot(matching: two, as: .image(size: CGSize(width: 100, height: 50))) } func testDefaultToggle() { - let one = Toggle(nil, isOn: Binding.constant(false)).skeleton(with: true) - let two = Toggle(isOn: nil, label: { Text(String()) }).skeleton(with: true) + let one = Toggle("", isOn: Binding.constant(false)).skeleton(with: true) + let two = Toggle(isOn: Binding.constant(Bool()), label: { Text(String()) }).skeleton(with: true) assertNamedSnapshot(matching: one, as: .image(size: CGSize(width: 100, height: 50))) assertNamedSnapshot(matching: two, as: .image(size: CGSize(width: 100, height: 50))) } func testCustomToggle() { - let one = Toggle(nil, isOn: Binding.constant(false)).skeleton(with: true, appearance: .gradient(.radial), shape: .rounded(.radius(10))) - let two = Toggle(isOn: nil, label: { Text(String()) }).skeleton(with: true, appearance: .gradient(.radial), shape: .rounded(.radius(10))) + let one = Toggle("", isOn: Binding.constant(false)).skeleton(with: true, appearance: .gradient(.radial), shape: .rounded(.radius(10))) + let two = Toggle(isOn: Binding.constant(Bool()), label: { Text(String()) }).skeleton(with: true, appearance: .gradient(.radial), shape: .rounded(.radius(10))) assertNamedSnapshot(matching: one, as: .image(size: CGSize(width: 100, height: 50))) assertNamedSnapshot(matching: two, as: .image(size: CGSize(width: 100, height: 50))) } func testDefaultSecureField() { - let view = SecureField(nil, text: Binding.constant(String())).skeleton(with: true) + let view = SecureField("", text: Binding.constant(String())).skeleton(with: true) assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 50))) } func testCustomSecureField() { - let view = SecureField(nil, text: Binding.constant(String())).skeleton(with: true, appearance: .gradient(.angular), shape: .ellipse) + let view = SecureField("", text: Binding.constant(String())).skeleton(with: true, appearance: .gradient(.angular), shape: .ellipse) assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 50))) } func testDefaultSkeletonList() { let view = SkeletonList(with: [#function]) { loading, item in - Text(item).skeleton(with: loading) + Text(item ?? "").skeleton(with: loading) } assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 25))) } func testLoadingSkeletonList() { let view = SkeletonList(with: [String]()) { loading, item in - Text(item).skeleton(with: loading) + Text(item ?? "").skeleton(with: loading) } assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 25))) } func testDefaultSkeletonForEach() { let view = SkeletonForEach(with: [#function]) { loading, item in - Text(item).skeleton(with: loading) + Text(item ?? "").skeleton(with: loading) } assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 25))) } func testLoadingSkeletonForEach() { let view = SkeletonList(with: [String]()) { loading, item in - Text(item).skeleton(with: loading) + Text(item ?? "").skeleton(with: loading) } assertNamedSnapshot(matching: view, as: .image(size: CGSize(width: 100, height: 25))) }