Merge branch 'feature/textLink' into 'develop'
don't default to .black See merge request BPHV_MIPS/vds_ios!5
This commit is contained in:
commit
47a3710cf4
@ -56,6 +56,8 @@
|
||||
EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2CE28ABEF2B00DAE764 /* Typography.swift */; };
|
||||
EAB1D2E628AE842000DAE764 /* Publisher+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */; };
|
||||
EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */; };
|
||||
EAC9257D29119B5400091998 /* TextLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9257C29119B5400091998 /* TextLink.swift */; };
|
||||
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925822911B35300091998 /* TextLinkCaret.swift */; };
|
||||
EAC925842911C63100091998 /* Colorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEDF28F49DB3003B3210 /* Colorable.swift */; };
|
||||
EAC9258C2911C9DE00091998 /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* TextEntryField.swift */; };
|
||||
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9258B2911C9DE00091998 /* EntryField.swift */; };
|
||||
@ -141,6 +143,8 @@
|
||||
EAB1D2CE28ABEF2B00DAE764 /* Typography.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typography.swift; sourceTree = "<group>"; };
|
||||
EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Publisher+Bind.swift"; sourceTree = "<group>"; };
|
||||
EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControlPublisher.swift; sourceTree = "<group>"; };
|
||||
EAC9257C29119B5400091998 /* TextLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLink.swift; sourceTree = "<group>"; };
|
||||
EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = "<group>"; };
|
||||
EAC925872911C9DE00091998 /* TextEntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
|
||||
EAC9258B2911C9DE00091998 /* EntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = "<group>"; };
|
||||
EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = "<group>"; };
|
||||
@ -193,6 +197,16 @@
|
||||
path = Button;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA0FC2BE2912D18200DF80B4 /* Buttons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5FC35BE128D513EB004EBEAC /* Button */,
|
||||
EAC9257E29119B5D00091998 /* TextLink */,
|
||||
EAC925812911B34300091998 /* TextLinkCaret */,
|
||||
);
|
||||
path = Buttons;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EA1F265F28B945070033E859 /* RadioSwatch */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -261,7 +275,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA4DB2FE28DCBC1900103EE3 /* Badge */,
|
||||
5FC35BE128D513EB004EBEAC /* Button */,
|
||||
EA0FC2BE2912D18200DF80B4 /* Buttons */,
|
||||
EAF7F092289985E200B287F5 /* Checkbox */,
|
||||
EA3362412892EF700071C351 /* Label */,
|
||||
EA89200B28B530F0006B9984 /* RadioBox */,
|
||||
@ -411,6 +425,22 @@
|
||||
path = Publishers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAC9257E29119B5D00091998 /* TextLink */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAC9257C29119B5400091998 /* TextLink.swift */,
|
||||
);
|
||||
path = TextLink;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAC925812911B34300091998 /* TextLinkCaret */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAC925822911B35300091998 /* TextLinkCaret.swift */,
|
||||
);
|
||||
path = TextLinkCaret;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAC925852911C9DE00091998 /* TextFields */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -594,6 +624,7 @@
|
||||
EAC9258C2911C9DE00091998 /* TextEntryField.swift in Sources */,
|
||||
EA3362402892EF6C0071C351 /* Label.swift in Sources */,
|
||||
EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */,
|
||||
EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */,
|
||||
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
|
||||
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */,
|
||||
EAA5EEB728ECC03A003B3210 /* ToolTipLabelAttribute.swift in Sources */,
|
||||
@ -641,6 +672,7 @@
|
||||
EA3361B8288B2AAA0071C351 /* ViewProtocol.swift in Sources */,
|
||||
EA3361BF288B2EA60071C351 /* Handlerable.swift in Sources */,
|
||||
EA3361A8288B23300071C351 /* UIColor.swift in Sources */,
|
||||
EAC9257D29119B5400091998 /* TextLink.swift in Sources */,
|
||||
EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */,
|
||||
5FC35BE328D51405004EBEAC /* Button.swift in Sources */,
|
||||
);
|
||||
|
||||
103
VDS/Components/Buttons/TextLink/TextLink.swift
Normal file
103
VDS/Components/Buttons/TextLink/TextLink.swift
Normal file
@ -0,0 +1,103 @@
|
||||
//
|
||||
// TextLink.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 11/1/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
import VDSFormControlsTokens
|
||||
import Combine
|
||||
|
||||
@objc(VDSTextLink)
|
||||
open class TextLink: Control {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var heightConstraint: NSLayoutConstraint?
|
||||
private var label = Label()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
open var text: String? { didSet { didChange() } }
|
||||
|
||||
open var size: ButtonSize = .large { didSet { didChange() }}
|
||||
|
||||
private var height: CGFloat {
|
||||
switch size {
|
||||
case .large:
|
||||
return 44
|
||||
case .small:
|
||||
return 32
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
required public init() {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Functions
|
||||
//--------------------------------------------------
|
||||
open override func initialSetup() {
|
||||
super.initialSetup()
|
||||
}
|
||||
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
|
||||
addSubview(label)
|
||||
|
||||
//add tapGesture to self
|
||||
publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in
|
||||
self?.sendActions(for: .touchUpInside)
|
||||
}.store(in: &subscribers)
|
||||
|
||||
//pin stackview to edges
|
||||
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||
label.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
||||
label.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
|
||||
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
||||
|
||||
heightConstraint = heightAnchor.constraint(equalToConstant: height)
|
||||
heightConstraint?.isActive = true
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
size = .large
|
||||
accessibilityCustomActions = []
|
||||
accessibilityTraits = .staticText
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
open override func updateView() {
|
||||
label.surface = surface
|
||||
label.disabled = disabled
|
||||
label.typograpicalStyle = size == .large ? TypographicalStyle.BodyLarge : TypographicalStyle.BodySmall
|
||||
label.text = text ?? ""
|
||||
label.attributes = [UnderlineLabelAttribute(location: 0, length: label.text!.count)]
|
||||
heightConstraint?.constant = height
|
||||
}
|
||||
|
||||
}
|
||||
304
VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift
Normal file
304
VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift
Normal file
@ -0,0 +1,304 @@
|
||||
//
|
||||
// TextLinkCaret.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 11/1/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
import VDSFormControlsTokens
|
||||
import Combine
|
||||
|
||||
public enum TextLinkCaretPosition: String, CaseIterable {
|
||||
case left, right
|
||||
}
|
||||
|
||||
@objc(VDSTextLinkCaret)
|
||||
open class TextLinkCaret: Control {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
private var heightConstraint: NSLayoutConstraint?
|
||||
|
||||
private var label = Label().with {
|
||||
$0.typograpicalStyle = TypographicalStyle.BoldBodyLarge
|
||||
}
|
||||
|
||||
private var caretView = CaretView().with {
|
||||
$0.size = CaretView.CaretSize.small(.vertical)
|
||||
$0.lineWidth = 2
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
open var text: String? { didSet { didChange() } }
|
||||
|
||||
open var iconPosition: TextLinkCaretPosition = .right { didSet { didChange() } }
|
||||
|
||||
private var height: CGFloat {
|
||||
44
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
required public init() {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: .zero)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Functions
|
||||
//--------------------------------------------------
|
||||
open override func initialSetup() {
|
||||
super.initialSetup()
|
||||
}
|
||||
|
||||
open override func setup() {
|
||||
super.setup()
|
||||
//add tapGesture to self
|
||||
publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in
|
||||
self?.sendActions(for: .touchUpInside)
|
||||
}.store(in: &subscribers)
|
||||
|
||||
//constraints
|
||||
heightAnchor.constraint(greaterThanOrEqualToConstant: height).isActive = true
|
||||
|
||||
let size = caretView.size!.dimensions()
|
||||
caretView.frame = .init(x: 0, y: 0, width: size.width, height: size.height)
|
||||
addSubview(label)
|
||||
label.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
||||
label.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
|
||||
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
private var caretLeadingConstraint: NSLayoutConstraint?
|
||||
private var caretTrailingConstraint: NSLayoutConstraint?
|
||||
private var labelConstraint: NSLayoutConstraint?
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
accessibilityCustomActions = []
|
||||
accessibilityTraits = .staticText
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
open override func updateView() {
|
||||
|
||||
var updatedText = text ?? ""
|
||||
|
||||
caretView.surface = surface
|
||||
caretView.disabled = disabled
|
||||
caretView.direction = iconPosition == .right ? CaretView.Direction.right : CaretView.Direction.left
|
||||
|
||||
let image = caretView.getImage()
|
||||
let location = iconPosition == .right ? updatedText.count + 1 : 0
|
||||
let textColor = label.textColorConfiguration.getColor(self)
|
||||
let imageAttribute = ImageLabelAttribute(location: location,
|
||||
length: 1,
|
||||
image: image,
|
||||
frame: .init(x: 0, y: 0, width: image.size.width, height: image.size.height),
|
||||
tintColor: textColor)
|
||||
label.surface = surface
|
||||
label.disabled = disabled
|
||||
label.text = iconPosition == .right ? "\(updatedText) " : " \(updatedText)"
|
||||
label.attributes = [imageAttribute]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
public func getImage() -> UIImage {
|
||||
let renderer = UIGraphicsImageRenderer(size: self.bounds.size)
|
||||
let image = renderer.image { ctx in
|
||||
self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
|
||||
}
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
internal class CaretView: View {
|
||||
//------------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//------------------------------------------------------
|
||||
private var caretPath: UIBezierPath = UIBezierPath()
|
||||
|
||||
public var lineWidth: CGFloat = 1 { didSet{ didChange() } }
|
||||
|
||||
public var direction: Direction = .right { didSet{ didChange() } }
|
||||
|
||||
public var size: CaretSize? { didSet{ didChange() } }
|
||||
|
||||
public var colorConfiguration: AnyColorable = DisabledSurfaceColorConfiguration().with {
|
||||
$0.disabled.lightColor = VDSColor.elementsSecondaryOnlight
|
||||
$0.disabled.darkColor = VDSColor.elementsSecondaryOndark
|
||||
$0.enabled.lightColor = VDSColor.elementsPrimaryOnlight
|
||||
$0.enabled.darkColor = VDSColor.elementsPrimaryOndark
|
||||
}.eraseToAnyColorable()
|
||||
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//------------------------------------------------------
|
||||
|
||||
/// Sizes of CaretView are derived from InVision design specs. They are provided for convenience.
|
||||
public enum CaretSize {
|
||||
case small(Orientation)
|
||||
case medium(Orientation)
|
||||
case large(Orientation)
|
||||
|
||||
/// Orientation based on the longest line of the view.
|
||||
public enum Orientation {
|
||||
case vertical
|
||||
case horizontal
|
||||
}
|
||||
|
||||
/// Dimensions of container; provided by InVision design.
|
||||
func dimensions() -> CGSize {
|
||||
|
||||
switch self {
|
||||
case .small(let o):
|
||||
return o == .vertical ? CGSize(width: 6.9, height: 10.96) : CGSize(width: 10.96, height: 6.9)
|
||||
|
||||
case .medium(let o):
|
||||
return o == .vertical ? CGSize(width: 9.9, height: 16.96) : CGSize(width: 16.96, height: 9.9)
|
||||
|
||||
case .large(let o):
|
||||
return o == .vertical ? CGSize(width: 14.9, height: 24.96) : CGSize(width: 24.96, height: 14.9)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Initialization
|
||||
//------------------------------------------------------
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
public convenience init(lineWidth: CGFloat) {
|
||||
self.init(frame: .zero)
|
||||
self.lineWidth = lineWidth
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
fatalError("CaretView xib not supported.")
|
||||
}
|
||||
|
||||
required public convenience init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
public convenience init(size: CaretSize){
|
||||
let dimensions = size.dimensions()
|
||||
self.init(frame: .init(x: 0, y: 0, width: dimensions.width, height: dimensions.height))
|
||||
self.size = size
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Setup
|
||||
//------------------------------------------------------
|
||||
|
||||
override open func setup() {
|
||||
super.setup()
|
||||
defaultState()
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Drawing
|
||||
//------------------------------------------------------
|
||||
|
||||
/// The direction the caret will be pointing to.
|
||||
public enum Direction: Int {
|
||||
case left
|
||||
case right
|
||||
case down
|
||||
case up
|
||||
}
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
caretPath.removeAllPoints()
|
||||
caretPath.lineJoinStyle = .miter
|
||||
caretPath.lineWidth = lineWidth
|
||||
|
||||
let inset = lineWidth / 2
|
||||
let halfWidth = frame.size.width / 2
|
||||
let halfHeight = frame.size.height / 2
|
||||
|
||||
switch direction {
|
||||
case .up:
|
||||
caretPath.move(to: CGPoint(x: inset, y: frame.size.height - inset))
|
||||
caretPath.addLine(to: CGPoint(x: halfWidth, y: inset))
|
||||
caretPath.addLine(to: CGPoint(x: frame.size.width, y: frame.size.height))
|
||||
|
||||
case .right:
|
||||
caretPath.move(to: CGPoint(x: inset, y: inset))
|
||||
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: halfHeight))
|
||||
caretPath.addLine(to: CGPoint(x: inset, y: frame.size.height - inset))
|
||||
|
||||
case .down:
|
||||
caretPath.move(to: CGPoint(x: inset, y: inset))
|
||||
caretPath.addLine(to: CGPoint(x: halfWidth, y: frame.size.height - inset))
|
||||
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: inset))
|
||||
|
||||
case .left:
|
||||
caretPath.move(to: CGPoint(x: frame.size.width - inset, y: inset))
|
||||
caretPath.addLine(to: CGPoint(x: inset, y: halfHeight))
|
||||
caretPath.addLine(to: CGPoint(x: frame.size.width - inset, y: frame.size.height - inset))
|
||||
}
|
||||
|
||||
let color = colorConfiguration.getColor(self)
|
||||
color.setStroke()
|
||||
caretPath.stroke()
|
||||
}
|
||||
|
||||
override func updateView() {
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//------------------------------------------------------
|
||||
public func setLineColor(_ color: UIColor) {
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
public func defaultState() {
|
||||
isOpaque = false
|
||||
isHidden = false
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
/// Ensure you have defined a CaretSize with Orientation before calling.
|
||||
public func setConstraints() {
|
||||
|
||||
guard let dimensions = size?.dimensions() else { return }
|
||||
|
||||
heightAnchor.constraint(equalToConstant: dimensions.height).isActive = true
|
||||
widthAnchor.constraint(equalToConstant: dimensions.width).isActive = true
|
||||
}
|
||||
}
|
||||
@ -12,11 +12,13 @@ public struct ImageLabelAttribute: AttachmentLabelAttributeModel {
|
||||
public enum Error: Swift.Error {
|
||||
case bundleNotFound
|
||||
case imageNotFound(String)
|
||||
case imageNotSet
|
||||
}
|
||||
public var id = UUID()
|
||||
public var location: Int
|
||||
public var length: Int
|
||||
public var imageName: String
|
||||
public var imageName: String?
|
||||
public var image: UIImage?
|
||||
public var frame: CGRect
|
||||
public var tintColor: UIColor
|
||||
public static func == (lhs: ImageLabelAttribute, rhs: ImageLabelAttribute) -> Bool {
|
||||
@ -27,18 +29,34 @@ public struct ImageLabelAttribute: AttachmentLabelAttributeModel {
|
||||
return id == equatable.id && range == equatable.range && imageName == equatable.imageName
|
||||
}
|
||||
|
||||
public func getAttachment() throws -> NSTextAttachment {
|
||||
guard let bundle = Bundle(identifier: "com.vzw.vds") else {
|
||||
throw Error.bundleNotFound
|
||||
}
|
||||
|
||||
guard let image = UIImage(named: imageName, in: bundle, with: nil) else {
|
||||
throw Error.imageNotFound(imageName)
|
||||
}
|
||||
|
||||
private func imageAttachment(image: UIImage) -> NSTextAttachment {
|
||||
let attachment = NSTextAttachment()
|
||||
attachment.image = image.withTintColor(tintColor)
|
||||
attachment.bounds = frame
|
||||
return attachment
|
||||
}
|
||||
|
||||
public func getAttachment() throws -> NSTextAttachment {
|
||||
|
||||
//get a local asset
|
||||
if let imageName {
|
||||
guard let bundle = Bundle(identifier: "com.vzw.vds") else {
|
||||
throw Error.bundleNotFound
|
||||
}
|
||||
|
||||
guard let image = UIImage(named: imageName, in: bundle, with: nil) else {
|
||||
throw Error.imageNotFound(imageName)
|
||||
}
|
||||
|
||||
return imageAttachment(image: image)
|
||||
|
||||
} //get from set image
|
||||
else if let image {
|
||||
return imageAttachment(image: image)
|
||||
|
||||
} else {
|
||||
throw Error.imageNotSet
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user