Rename Image to ImageView, add Image props (#55)

This allows adding props for components that accept images, for example `Switch` is now able to implement `onImage` and `offImage` props.

* Add separate (empty for now) Image prop
* Implement Image, add Switch {on,off}Image props
This commit is contained in:
Max Desiatov 2019-02-27 08:54:49 +00:00 committed by GitHub
parent 570c2677d6
commit a570352abc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 142 additions and 98 deletions

View File

@ -18,9 +18,9 @@ struct ImageExample: PureLeafComponent {
axis: .vertical,
distribution: .fillEqually
), [
Image.node(.init(
ImageView.node(.init(
Style(contentMode: .scaleAspectFit),
name: "tokamak"
image: Image(name: "tokamak")
)),
])
}

View File

@ -1,68 +0,0 @@
//
// Image.swift
// Tokamak
//
// Created by Matvii Hodovaniuk on 2/17/19.
//
import Foundation
public struct Image: HostComponent {
public typealias Children = [AnyNode]
public struct Props: Equatable, StyleProps {
public enum RenderingMode {
case automatic
case alwaysOriginal
case alwaysTemplate
}
public enum Source: Equatable {
case name(String)
case data(Data)
}
// when changed initializes new image with `UIImage(named:)`
// or `UIImage(data:)`
public let source: Source
// when changed creates new image with `withRenderingMode`
public let renderingMode: RenderingMode
// when changed initializes new image with given scale
public let scale: Double
// mirrors `flipsForRightToLeftLayoutDirection`
public let flipsForRTL: Bool
public let style: Style?
public init(
_ style: Style? = nil,
flipsForRTL: Bool = false,
name: String,
renderingMode: RenderingMode = .automatic,
scale: Double = 1.0
) {
source = .name(name)
self.renderingMode = renderingMode
self.scale = scale
self.flipsForRTL = flipsForRTL
self.style = style
}
public init(
_ style: Style? = nil,
data: Data,
flipsForRTL: Bool = false,
renderingMode: RenderingMode = .automatic,
scale: Double = 1.0
) {
source = .data(data)
self.renderingMode = renderingMode
self.scale = scale
self.flipsForRTL = flipsForRTL
self.style = style
}
}
}

View File

@ -0,0 +1,23 @@
//
// ImageView.swift
// Tokamak
//
// Created by Matvii Hodovaniuk on 2/17/19.
//
public struct ImageView: HostComponent {
public typealias Children = [AnyNode]
public struct Props: Equatable, StyleProps {
public let image: Image
public let style: Style?
public init(
_ style: Style? = nil,
image: Image
) {
self.image = image
self.style = style
}
}
}

View File

@ -14,12 +14,16 @@ public struct Switch: HostComponent {
public let valueHandler: Handler<Bool>?
public let isEnabled: Bool
public let isAnimated: Bool
public let onImage: Image?
public let offImage: Image?
public init(
_ style: Style? = nil,
handlers: EventHandlers = [:],
isAnimated: Bool = true,
isEnabled: Bool = true,
offImage: Image? = nil,
onImage: Image? = nil,
value: Bool,
valueHandler: Handler<Bool>? = nil
) {
@ -29,6 +33,8 @@ public struct Switch: HostComponent {
self.valueHandler = valueHandler
self.isEnabled = isEnabled
self.isAnimated = isAnimated
self.offImage = offImage
self.onImage = onImage
}
}

View File

@ -0,0 +1,57 @@
//
// Image.swift
// Tokamak
//
// Created by Max Desiatov on 26/02/2019.
//
import Foundation
public struct Image: Equatable {
public enum RenderingMode {
case automatic
case alwaysOriginal
case alwaysTemplate
}
public enum Source: Equatable {
case name(String)
case data(Data)
}
/// when changed initializes new image with given data or name
public let source: Source
/// when changed creates new image with `withRenderingMode`
public let renderingMode: RenderingMode
/// equivalent to `flipsForRightToLeftLayoutDirection` in UIKit
public let flipsForRTL: Bool
// when changed initializes new image with given scale
public let scale: Double
public init(
flipsForRTL: Bool = false,
name: String,
renderingMode: RenderingMode = .automatic,
scale: Double = 1.0
) {
source = .name(name)
self.renderingMode = renderingMode
self.scale = scale
self.flipsForRTL = flipsForRTL
}
public init(
data: Data,
flipsForRTL: Bool = false,
renderingMode: RenderingMode = .automatic,
scale: Double = 1.0
) {
source = .data(data)
self.renderingMode = renderingMode
self.scale = scale
self.flipsForRTL = flipsForRTL
}
}

View File

@ -15,7 +15,7 @@ final class TokamakImage: UIImageView, Default {
}
extension UIImage.RenderingMode {
public init(_ rawValue: Image.Props.RenderingMode) {
public init(_ rawValue: Image.RenderingMode) {
switch rawValue {
case .automatic:
self = .automatic
@ -27,27 +27,14 @@ extension UIImage.RenderingMode {
}
}
extension Image: UIViewComponent {
extension ImageView: UIViewComponent {
public typealias RefTarget = UIImageView
static func update(
view box: ViewBox<TokamakImage>,
_ props: Image.Props,
_ props: ImageView.Props,
_ children: [AnyNode]
) {
var image: UIImage?
switch props.source {
case let .name(name):
image = UIImage(named: name)
case let .data(data):
image = UIImage(data: data, scale: CGFloat(props.scale))
}
if props.flipsForRTL {
image = image?.imageFlippedForRightToLeftLayoutDirection()
}
box.view.image = image?.withRenderingMode(.init(props.renderingMode))
box.view.image = UIImage.from(image: props.image)
}
}

View File

@ -41,7 +41,7 @@ extension Label: UIViewComponent {
view.textAlignment = NSTextAlignment(props.alignment)
view.numberOfLines = props.numberOfLines
view.lineBreakMode = NSLineBreakMode(props.lineBreakMode)
props.textColor.flatMap { view.textColor = UIColor($0) }
view.textColor = props.textColor.flatMap { UIColor($0) }
view.text = children
}
}

View File

@ -32,6 +32,9 @@ extension Switch: UIValueComponent {
static func update(valueBox: ValueControlBox<TokamakSwitch>,
_ props: Switch.Props,
_ children: Null) {
valueBox.view.isAnimated = props.isAnimated
let view = valueBox.view
view.isAnimated = props.isAnimated
view.onImage = props.onImage.flatMap { UIImage.from(image: $0) }
view.offImage = props.onImage.flatMap { UIImage.from(image: $0) }
}
}

View File

@ -0,0 +1,28 @@
//
// Image.swift
// Tokamak
//
// Created by Max Desiatov on 26/02/2019.
//
import Tokamak
import UIKit
extension UIImage {
static func from(image: Image) -> UIImage? {
var result: UIImage?
switch image.source {
case let .name(name):
result = UIImage(named: name)
case let .data(data):
result = UIImage(data: data, scale: CGFloat(image.scale))
}
if image.flipsForRTL {
result = result?.imageFlippedForRightToLeftLayoutDirection()
}
return result
}
}

View File

@ -25,8 +25,10 @@
A6AB60B5221C70340063F88A /* ContentMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6AB60B4221C70340063F88A /* ContentMode.swift */; };
A6D188EC221F1CA300C3947C /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D188EB221F1CA300C3947C /* Accessibility.swift */; };
A6D188EE2220221B00C3947C /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D188ED2220221B00C3947C /* TextField.swift */; };
D1B4F8DB221AFB0E00C53C42 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B4F8D9221AFB0800C53C42 /* Image.swift */; };
D1B4F8DD221AFB2B00C53C42 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B4F8DC221AFB2B00C53C42 /* Image.swift */; };
D1B4F8DB221AFB0E00C53C42 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B4F8D9221AFB0800C53C42 /* ImageView.swift */; };
D1B4F8DD221AFB2B00C53C42 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B4F8DC221AFB2B00C53C42 /* ImageView.swift */; };
D1CFC81D222546F500B03222 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1CFC81C222546F500B03222 /* Image.swift */; };
D1CFC8202225622D00B03222 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1CFC81E222561AD00B03222 /* Image.swift */; };
OBJ_153 /* AnyEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_66 /* AnyEquatable.swift */; };
OBJ_154 /* AnyNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_67 /* AnyNode.swift */; };
OBJ_155 /* Components.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_68 /* Components.swift */; };
@ -190,8 +192,10 @@
A6D188EB221F1CA300C3947C /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = "<group>"; };
A6D188ED2220221B00C3947C /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
A6D188EF2220222F00C3947C /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
D1B4F8D9221AFB0800C53C42 /* Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
D1B4F8DC221AFB2B00C53C42 /* Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
D1B4F8D9221AFB0800C53C42 /* ImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = "<group>"; };
D1B4F8DC221AFB2B00C53C42 /* ImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = "<group>"; };
D1CFC81C222546F500B03222 /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
D1CFC81E222561AD00B03222 /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Image.swift; sourceTree = "<group>"; };
OBJ_10 /* ContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerViewController.swift; sourceTree = "<group>"; };
OBJ_100 /* FirstBaseline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstBaseline.swift; sourceTree = "<group>"; };
OBJ_101 /* Height.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Height.swift; sourceTree = "<group>"; };
@ -418,9 +422,9 @@
OBJ_17 /* Host */ = {
isa = PBXGroup;
children = (
D1B4F8D9221AFB0800C53C42 /* Image.swift */,
OBJ_18 /* Button.swift */,
OBJ_19 /* DatePicker.swift */,
D1B4F8D9221AFB0800C53C42 /* ImageView.swift */,
OBJ_20 /* Label.swift */,
OBJ_21 /* ListView.swift */,
OBJ_22 /* ModalPresenter.swift */,
@ -443,6 +447,7 @@
OBJ_32 /* Color.swift */,
OBJ_33 /* Constraint */,
OBJ_52 /* Event.swift */,
D1CFC81E222561AD00B03222 /* Image.swift */,
OBJ_53 /* LineBreakMode.swift */,
OBJ_54 /* Rectangle.swift */,
A6AB60B4221C70340063F88A /* ContentMode.swift */,
@ -555,11 +560,11 @@
OBJ_70 /* Host */ = {
isa = PBXGroup;
children = (
D1B4F8DC221AFB2B00C53C42 /* Image.swift */,
OBJ_71 /* Alert.swift */,
OBJ_72 /* Animated.swift */,
OBJ_73 /* Button.swift */,
OBJ_74 /* DatePicker.swift */,
D1B4F8DC221AFB2B00C53C42 /* ImageView.swift */,
OBJ_75 /* Label.swift */,
OBJ_76 /* ListView.swift */,
OBJ_77 /* NavigationController.swift */,
@ -568,8 +573,8 @@
OBJ_80 /* StackView.swift */,
OBJ_81 /* Stepper.swift */,
OBJ_82 /* Switch.swift */,
OBJ_83 /* View.swift */,
A6D188ED2220221B00C3947C /* TextField.swift */,
OBJ_83 /* View.swift */,
);
path = Host;
sourceTree = "<group>";
@ -619,6 +624,7 @@
OBJ_93 /* Constraint */,
OBJ_110 /* Event.swift */,
OBJ_111 /* Insets.swift */,
D1CFC81C222546F500B03222 /* Image.swift */,
OBJ_112 /* LineBreakMode.swift */,
OBJ_113 /* Rectangle.swift */,
OBJ_114 /* Second.swift */,
@ -781,6 +787,7 @@
OBJ_159 /* DatePicker.swift in Sources */,
OBJ_160 /* Label.swift in Sources */,
OBJ_161 /* ListView.swift in Sources */,
D1CFC81D222546F500B03222 /* Image.swift in Sources */,
OBJ_162 /* NavigationController.swift in Sources */,
OBJ_163 /* SegmentedControl.swift in Sources */,
OBJ_164 /* Slider.swift in Sources */,
@ -798,7 +805,7 @@
OBJ_176 /* Bottom.swift in Sources */,
A6D188EE2220221B00C3947C /* TextField.swift in Sources */,
OBJ_177 /* Center.swift in Sources */,
D1B4F8DD221AFB2B00C53C42 /* Image.swift in Sources */,
D1B4F8DD221AFB2B00C53C42 /* ImageView.swift in Sources */,
A6D188EC221F1CA300C3947C /* Accessibility.swift in Sources */,
OBJ_178 /* CenterX.swift in Sources */,
OBJ_179 /* CenterY.swift in Sources */,
@ -896,8 +903,9 @@
OBJ_276 /* CenterX.swift in Sources */,
OBJ_277 /* CenterY.swift in Sources */,
OBJ_278 /* Constrainable.swift in Sources */,
D1B4F8DB221AFB0E00C53C42 /* Image.swift in Sources */,
D1B4F8DB221AFB0E00C53C42 /* ImageView.swift in Sources */,
OBJ_279 /* Constraint.swift in Sources */,
D1CFC8202225622D00B03222 /* Image.swift in Sources */,
OBJ_280 /* FirstBaseline.swift in Sources */,
OBJ_281 /* Height.swift in Sources */,
OBJ_282 /* LastBaseline.swift in Sources */,