Cyborg/XMLSchema.swift (162 lines of code) (raw):

// // Copyright (c) 2018. Uber Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // import Foundation #if os(macOS) import AppKit #else import UIKit #endif /// Elements of a VectorDrawable document. enum Element: String { case vector case path case group case clipPath = "clip-path" case item } /// Elements of the <vector> element of a VectorDrawable document. enum VectorProperty: String { case schema = "xmlns:android" case resourceSchema = "xmlns:aapt" case height = "android:height" case width = "android:width" case viewPortHeight = "android:viewportHeight" case viewPortWidth = "android:viewportWidth" case tint = "android:tint" case tintMode = "android:tintMode" case autoMirrored = "android:autoMirrored" case alpha = "android:alpha" } /// Elements of the <path> element of a VectorDrawable document enum PathProperty: String { case name = "android:name" case pathData = "android:pathData" case fillColor = "android:fillColor" case strokeColor = "android:strokeColor" case strokeWidth = "android:strokeWidth" case strokeAlpha = "android:strokeAlpha" case fillAlpha = "android:fillAlpha" case trimPathStart = "android:trimPathStart" case trimPathEnd = "android:trimPathEnd" case trimPathOffset = "android:trimPathOffset" case strokeLineCap = "android:strokeLineCap" case strokeLineJoin = "android:strokeLineJoin" case strokeMiterLimit = "android:strokeMiterLimit" case fillType = "android:fillType" } /// Elements of the <clip-path> element of a VectorDrawable document. enum ClipPathProperty: String { case name = "android:name" case pathData = "android:pathData" case fillType = "android:fillType" case fillColor = "android:fillColor" case strokeColor = "android:strokeColor" } /// Elements of the <group> element of a VectorDrawable document enum GroupProperty: String { case name = "android:name" case rotation = "android:rotation" case pivotX = "android:pivotX" case pivotY = "android:pivotY" case scaleX = "android:scaleX" case scaleY = "android:scaleY" case translateX = "android:translateX" case translateY = "android:translateY" } enum Color: Equatable { case theme(name: String) case hex(value: UIColor) case resource(named: String) init?(_ string: XMLString) { if string.count == 0 { return nil } else if string[safeIndex: 0] == .questionMark { if string.count > 1 { self = .theme(name: String(copying: string[1..<string.count])) } else { return nil } } else if string[safeIndex: 0] == .at { if string.count > 1 { self = .resource(named: String(copying: string[1..<string.count])) } else { return nil } } else { let hasAlpha = (string.count == 9) // munge the string into a form that Init.init(_:, radix:) can understand var withoutLeadingHashTag = String(withoutCopying: string) _ = withoutLeadingHashTag.remove(at: withoutLeadingHashTag.startIndex) if withoutLeadingHashTag.count == 3 { // convert from shorthand hexadecimal form, which doesn't work with the init withoutLeadingHashTag.append(withoutLeadingHashTag) } if let value = Int64(withoutLeadingHashTag, radix: 16) { func component(_ mask: Int64, _ shift: Int64) -> CGFloat { return CGFloat((value & mask) >> shift) / 255 } let alpha = hasAlpha ? component(0xFF000000, 24) : 1.0 let color = UIColor(red: component(0xFF0000, 16), green: component(0xFF00, 8), blue: component(0xFF, 0), alpha: alpha) self = .hex(value: color) } else { return nil } } } func color(from externalValues: ExternalValues) -> UIColor { switch self { case .hex(let value): return value case .theme(let name): return externalValues.colorFromTheme(named: name) case .resource(named: let name): return externalValues.colorFromResources(named: name) } } } enum LineCap: String, XMLStringRepresentable { case butt case round case square var intoCoreAnimation: CAShapeLayerLineCap { switch self { case .butt: return .butt case .round: return .round case .square: return .square } } } enum LineJoin: String, XMLStringRepresentable { case miter case round case bevel var intoCoreAnimation: CAShapeLayerLineJoin { switch self { case .bevel: return .bevel case .round: return .round case .miter: return .miter } } } enum GradientProperty: String, XMLStringRepresentable { case startY = "android:startY" case startX = "android:startX" case endY = "android:endY" case endX = "android:endX" case type = "android:type" case startcolor = "android:startColor" case endColor = "android:endColor" case centerColor = "android:centerColor" case tileMode = "android:tileMode" case centerX = "android:centerX" case centerY = "android:centerY" case gradientRadius = "android:gradientRadius" } enum GradientType: String, XMLStringRepresentable { case linear case radial case sweep } enum ItemProperty: String, XMLStringRepresentable { case offset = "android:offset" case color = "android:color" } enum TileMode: String, XMLStringRepresentable { case clamp case `repeat` case mirror }