Skip to content

Commit

Permalink
[Issue-47] Add SystemImage protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Pospesel authored and mpospese committed Mar 9, 2023
1 parent e640ed3 commit d72ddbc
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 1 deletion.
1 change: 0 additions & 1 deletion Sources/YCoreUI/Protocols/ImageAsset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// Copyright © 2022 Y Media Labs. All rights reserved.
//

import Foundation
import UIKit

/// Any named image asset can be loaded from an asset catalog.
Expand Down
54 changes: 54 additions & 0 deletions Sources/YCoreUI/Protocols/SystemImage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// SystemImage.swift
// YCoreUI
//
// Created by Mark Pospesel on 3/8/23.
// Copyright © 2023 Y Media Labs. All rights reserved.
//

import UIKit

/// Any string corresponding to a system image (SF Symbols).
///
/// All properties and functions have default implementations. At a minimum just have your string-based enum conform
/// to `SystemImage`. The raw value of the enum should match a sytem image name (e.g. `checkmark.seal`).
public protocol SystemImage: RawRepresentable where RawValue == String {
/// Fallback image to use in case a system image cannot be loaded.
/// (default is a 16 x 16 square filled with `.systemPink`)
static var fallbackImage: UIImage { get }

/// A system image for this name value.
///
/// Default implementation calls `loadImage` and nil-coalesces to `fallbackImage`.
var image: UIImage { get }

/// Loads the named system image.
/// - Returns: The named system image or else `nil` if the system image cannot be loaded.
func loadImage() -> UIImage?
}

extension SystemImage {
/// Fallback image to use in case a system image cannot be loaded.
/// (default is a 16 x 16 square filled with `.systemPink`)
public static var fallbackImage: UIImage {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 16, height: 16))
let image = renderer.image { ctx in
UIColor.systemPink.setFill()
ctx.fill(CGRect(origin: .zero, size: renderer.format.bounds.size))
}
return image
}

/// Loads the named system image.
///
/// Default implementation uses `UIImage(systemName:)` passing in the associated `rawValue`.
/// - Returns: The named system image or else `nil` if the system image cannot be loaded.
public func loadImage() -> UIImage? {
UIImage(systemName: rawValue)
}

/// A system image for this name value.
///
/// Default implementation calls `loadImage` and nil-coalesces to `fallbackImage`.
public var image: UIImage { loadImage() ?? Self.fallbackImage }
}
57 changes: 57 additions & 0 deletions Tests/YCoreUITests/Protocols/SystemImageTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// SystemImageTests.swift
// YCoreUI
//
// Created by Mark Pospesel on 3/8/23.
// Copyright © 2023 Y Media Labs. All rights reserved.
//

import XCTest
import YCoreUI

final class SystemImageTests: XCTestCase {
func test_fallbackImage_deliversImage() {
XCTAssertNotNil(Symbols.fallbackImage)
XCTAssertEqual(MissingSymbols.fallbackImage, UIImage(systemName: "x.squareroot"))
}

func test_loadImage_deliversImage() {
Symbols.allCases.forEach {
XCTAssertNotNil($0.loadImage())
}
}

func test_missingImage_deliversCustomFallback() {
MissingSymbols.allCases.forEach {
XCTAssertNil($0.loadImage())
XCTAssertEqual($0.image, UIImage(systemName: "x.squareroot"))
}
}

func test_systemImage_deliversDefaultFallback() {
XCTAssertEqual(DefaultSymbols.defaultCase.image.pngData(), DefaultSymbols.fallbackImage.pngData())
}
}

extension SystemImageTests {
enum Symbols: String, CaseIterable, SystemImage {
case checked = "checkmark.square"
case unchecked = "square"
case warning = "exclamationmark.triangle.fill"
case error = "exclamationmark.octagon"
}

enum MissingSymbols: String, CaseIterable, SystemImage {
case notHere
case gone

static var fallbackImage: UIImage {
let image: UIImage! = UIImage(systemName: "x.squareroot")
return image
}
}

enum DefaultSymbols: String, CaseIterable, SystemImage {
case defaultCase
}
}

0 comments on commit d72ddbc

Please sign in to comment.