Skip to content

Commit d72ddbc

Browse files
Mark Pospeselmpospese
Mark Pospesel
authored andcommitted
[Issue-47] Add SystemImage protocol
1 parent e640ed3 commit d72ddbc

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed

Sources/YCoreUI/Protocols/ImageAsset.swift

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// Copyright © 2022 Y Media Labs. All rights reserved.
77
//
88

9-
import Foundation
109
import UIKit
1110

1211
/// Any named image asset can be loaded from an asset catalog.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// SystemImage.swift
3+
// YCoreUI
4+
//
5+
// Created by Mark Pospesel on 3/8/23.
6+
// Copyright © 2023 Y Media Labs. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
/// Any string corresponding to a system image (SF Symbols).
12+
///
13+
/// All properties and functions have default implementations. At a minimum just have your string-based enum conform
14+
/// to `SystemImage`. The raw value of the enum should match a sytem image name (e.g. `checkmark.seal`).
15+
public protocol SystemImage: RawRepresentable where RawValue == String {
16+
/// Fallback image to use in case a system image cannot be loaded.
17+
/// (default is a 16 x 16 square filled with `.systemPink`)
18+
static var fallbackImage: UIImage { get }
19+
20+
/// A system image for this name value.
21+
///
22+
/// Default implementation calls `loadImage` and nil-coalesces to `fallbackImage`.
23+
var image: UIImage { get }
24+
25+
/// Loads the named system image.
26+
/// - Returns: The named system image or else `nil` if the system image cannot be loaded.
27+
func loadImage() -> UIImage?
28+
}
29+
30+
extension SystemImage {
31+
/// Fallback image to use in case a system image cannot be loaded.
32+
/// (default is a 16 x 16 square filled with `.systemPink`)
33+
public static var fallbackImage: UIImage {
34+
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 16, height: 16))
35+
let image = renderer.image { ctx in
36+
UIColor.systemPink.setFill()
37+
ctx.fill(CGRect(origin: .zero, size: renderer.format.bounds.size))
38+
}
39+
return image
40+
}
41+
42+
/// Loads the named system image.
43+
///
44+
/// Default implementation uses `UIImage(systemName:)` passing in the associated `rawValue`.
45+
/// - Returns: The named system image or else `nil` if the system image cannot be loaded.
46+
public func loadImage() -> UIImage? {
47+
UIImage(systemName: rawValue)
48+
}
49+
50+
/// A system image for this name value.
51+
///
52+
/// Default implementation calls `loadImage` and nil-coalesces to `fallbackImage`.
53+
public var image: UIImage { loadImage() ?? Self.fallbackImage }
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// SystemImageTests.swift
3+
// YCoreUI
4+
//
5+
// Created by Mark Pospesel on 3/8/23.
6+
// Copyright © 2023 Y Media Labs. All rights reserved.
7+
//
8+
9+
import XCTest
10+
import YCoreUI
11+
12+
final class SystemImageTests: XCTestCase {
13+
func test_fallbackImage_deliversImage() {
14+
XCTAssertNotNil(Symbols.fallbackImage)
15+
XCTAssertEqual(MissingSymbols.fallbackImage, UIImage(systemName: "x.squareroot"))
16+
}
17+
18+
func test_loadImage_deliversImage() {
19+
Symbols.allCases.forEach {
20+
XCTAssertNotNil($0.loadImage())
21+
}
22+
}
23+
24+
func test_missingImage_deliversCustomFallback() {
25+
MissingSymbols.allCases.forEach {
26+
XCTAssertNil($0.loadImage())
27+
XCTAssertEqual($0.image, UIImage(systemName: "x.squareroot"))
28+
}
29+
}
30+
31+
func test_systemImage_deliversDefaultFallback() {
32+
XCTAssertEqual(DefaultSymbols.defaultCase.image.pngData(), DefaultSymbols.fallbackImage.pngData())
33+
}
34+
}
35+
36+
extension SystemImageTests {
37+
enum Symbols: String, CaseIterable, SystemImage {
38+
case checked = "checkmark.square"
39+
case unchecked = "square"
40+
case warning = "exclamationmark.triangle.fill"
41+
case error = "exclamationmark.octagon"
42+
}
43+
44+
enum MissingSymbols: String, CaseIterable, SystemImage {
45+
case notHere
46+
case gone
47+
48+
static var fallbackImage: UIImage {
49+
let image: UIImage! = UIImage(systemName: "x.squareroot")
50+
return image
51+
}
52+
}
53+
54+
enum DefaultSymbols: String, CaseIterable, SystemImage {
55+
case defaultCase
56+
}
57+
}

0 commit comments

Comments
 (0)