diff --git a/Package.swift b/Package.swift index eb1eb6a..b23f2aa 100644 --- a/Package.swift +++ b/Package.swift @@ -1,13 +1,17 @@ import PackageDescription let package = Package( - name: "UXKit", - - exclude: [ - "UXKit.xcodeproj", - "GNUmakefile", - "LICENSE", - "README.md", - "xcconfig" - ] + name: "UXKit", + + platforms: [ + .macOS(.v10_15), .iOS(.v13), .tvOS(.v13) + ], + + exclude: [ + "UXKit.xcodeproj", + "GNUmakefile", + "LICENSE", + "README.md", + "xcconfig" + ] ) diff --git a/Package@swift-5.1.swift b/Package@swift-5.1.swift index 2a2e82a..da64e0a 100644 --- a/Package@swift-5.1.swift +++ b/Package@swift-5.1.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "UXKit", platforms: [ - .macOS(.v10_12), .iOS(.v10) + .macOS(.v10_13), .iOS(.v13), .tvOS(.v13) ], products: [ .library(name: "UXKit", targets: ["UXKit"]), diff --git a/Package@swift-5.swift b/Package@swift-5.swift index 679dc5d..d0dc071 100644 --- a/Package@swift-5.swift +++ b/Package@swift-5.swift @@ -3,12 +3,15 @@ import PackageDescription let package = Package( - name: "UXKit", - products: [ - .library(name: "UXKit", targets: ["UXKit"]), - ], - dependencies: [], - targets: [ - .target(name:"UXKit") - ] + name: "UXKit", + platforms: [ + .macOS(.v10_13), .iOS(.v13), .tvOS(.v13) + ], + products: [ + .library(name: "UXKit", targets: ["UXKit"]), + ], + dependencies: [], + targets: [ + .target(name:"UXKit") + ] ) diff --git a/Sources/UXKit/AppKit/NSTableViewCell.swift b/Sources/UXKit/AppKit/NSTableViewCell.swift index 56c4642..7ee3281 100644 --- a/Sources/UXKit/AppKit/NSTableViewCell.swift +++ b/Sources/UXKit/AppKit/NSTableViewCell.swift @@ -21,7 +21,7 @@ * * NOTE: This one doesn't actually support an image :-/ */ - open class NSTableViewCell : NSTableCellView { + open class NSTableViewCell : NSTableCellView, NSTextFieldDelegate { // Note: UITableViewCell has many more views to show selection state, // regular background, etc. @@ -56,6 +56,53 @@ } private let style = Style() + // provided for compatibility, though not really used. + public enum SelectionStyle : Int { + case none = 0 + case blue = 1 + case gray = 2 + @available(iOS 7.0, *) + case `default` = 3 + } + + public var selectionStyle : SelectionStyle = .default + + // provided for compatibility, though not really used. + public enum AccessoryType : Int { + case none = 0 // don't show any accessory view + case disclosureIndicator = 1 // regular chevron. doesn't track + case detailDisclosureButton = 2 // info button w/ chevron. tracks + case checkmark = 3 // checkmark. doesn't track + + @available(iOS 7.0, *) + case detailButton = 4 // info button. tracks + } + + public var accessoryType : AccessoryType = .none + + + // provided for compatibility, though not really used. + public enum EditingStyle : Int { + case none = 0 + case delete = 1 + case insert = 2 + } + + // These are provided for UIKit compatibility. Not actively used (yet). + public var backgroundColor : UXColor { + get { + if let col = self.layer?.backgroundColor { + return UXColor(cgColor: col)! + } + + return UXColor.textBackgroundColor + } + + set { + self.layer?.backgroundColor = newValue.cgColor + } + } + public init(style: UXTableViewCellStyle, reuseIdentifier id: String?) { /* TODO: SETUP: default: just label, no detail @@ -63,7 +110,8 @@ value1: blue lable on the left 1/4, black detail on the right (same row) subtitle: label, below gray detail (two rows) */ - + editing = false + super.init(frame: UXRect()) if let id = id { @@ -80,7 +128,7 @@ } private var installedConstraintSetup = ViewSetup.none - private var requiredContraintSetup : ViewSetup { + private var requiredConstraintSetup : ViewSetup { switch ( _textLabel, _detailTextLabel ) { case ( .none, .none ): return .none case ( .some, .none ): return .label @@ -93,7 +141,7 @@ override open func updateConstraints() { super.updateConstraints() - let required = requiredContraintSetup + let required = requiredConstraintSetup guard installedConstraintSetup != required else { return } // Swift.print("from \(installedConstraintSetup) to \(required)") @@ -156,7 +204,7 @@ let label = makeLabel() label.font = UXFont.systemFont(ofSize: style.labelSize) label.cell?.lineBreakMode = .byTruncatingTail - + #if false label.verticalAlignment = .middleAlignment // TBD: do we want this? // I'm still not quite sure why we even need this. The height of the @@ -179,6 +227,84 @@ return label } } + + public override var acceptsFirstResponder: Bool { + get { + return true + } + } + + public override func becomeFirstResponder() -> Bool { + if !self.editing { + self.editing = true + + if let label = _textLabel { + if #available(macOS 10.14, *) { + label.backgroundColor = .selectedContentBackgroundColor + } else { + // Fallback on earlier versions + label.backgroundColor = .selectedMenuItemColor + } + + label.drawsBackground = true + label.isEditable = true + label.target = self + label.action = #selector(didEditTableRow(_ :)) + label.becomeFirstResponder() + + if label.delegate == nil { + label.delegate = self + } + + if let del = label.delegate as? UXTextFieldDelegate { + del.textFieldDidBeginEditing(label) + } + } + + return true + } + + return false + } + + public override func resignFirstResponder() -> Bool { + if self.editing { + self.editing = false + + if let label = _textLabel { + label.drawsBackground = false + label.abortEditing() + label.isEditable = false + + if let del = label.delegate as? UXTextFieldDelegate { + del.textFieldDidEndEditing(label) + } + } + } + + return true + } + + var editing : Bool + + @objc func didEditTableRow(_ editor: Any) { + NSLog("row was edited") + if let label = _textLabel { + if let del = label.delegate as? UXTextFieldDelegate { + if del.textFieldShouldReturn(label) { + // Only actually end the editing if the delegate says to. + _ = self.resignFirstResponder() + } + } else { + // if the delegate is not an instance of UXTextFieldDelegate, meaning it + // doesn't support the UIKit enhancements, then just treat this as an end + // to editing. + // + _ = self.resignFirstResponder() + } + } + } + var _detailTextLabel : UXLabel? = nil open var detailTextLabel : UXLabel? { @@ -224,7 +350,6 @@ } } - // MARK: - Separator line (TBD: should we draw this?) open var dividerColor : UXColor { return UXColor.lightGray } @@ -249,19 +374,20 @@ // MARK: - Label Factory open func makeLabel() -> UXLabel { - let v = NSTextField(frame: UXRect()) - v.translatesAutoresizingMaskIntoConstraints = false - - /* configure as label */ - v.isEditable = false - v.isBezeled = false - v.drawsBackground = false - v.isSelectable = false // not for raw labels - - /* common */ - v.alignment = .left - - return v + let v = UXLabel(frame: UXRect()) + v.cell = VerticallyCenteredTextFieldCell() + v.translatesAutoresizingMaskIntoConstraints = false + + /* configure as label */ + v.isEditable = false + v.isBezeled = false + v.drawsBackground = false + v.isSelectable = false // not for raw labels + + /* common */ + v.alignment = .center + + return v } } diff --git a/Sources/UXKit/AppKit/UXGestures-AppKit.swift b/Sources/UXKit/AppKit/UXGestures-AppKit.swift index 8237592..057e7f3 100644 --- a/Sources/UXKit/AppKit/UXGestures-AppKit.swift +++ b/Sources/UXKit/AppKit/UXGestures-AppKit.swift @@ -7,6 +7,7 @@ import Cocoa public typealias UXGestureRecognizer = NSGestureRecognizer + public typealias UXGestureRecognizerDelegate = NSGestureRecognizerDelegate public typealias UXRotationGestureRecognizer = NSRotationGestureRecognizer public typealias UXPanGestureRecognizer = NSPanGestureRecognizer public typealias UXTapGestureRecognizer = NSClickGestureRecognizer @@ -16,6 +17,14 @@ public extension NSView { + enum SwipeDirection { + case none + case left + case right + case up + case down + } + @discardableResult func on(gesture gr: UXGestureRecognizer, target: AnyObject, action: Selector) -> Self @@ -26,6 +35,25 @@ return self } + // This is how macOS handles Swipe gestures. + override func swipe(with event: NSEvent) { + let x : CGFloat = event.deltaX + let y : CGFloat = event.deltaY + var direction : SwipeDirection = .none + + if (x != 0) { + direction = (x > 0) ? .left : .right + } else if (y != 0) { + direction = (y > 0) ? .up : .down + } + + self.swipeGestureRecognized(inDirection: direction) + } + + // Override this if you want to receive swipe gestures on your NSView. + func swipeGestureRecognized(inDirection direction: SwipeDirection) { + } + } public extension UXTapGestureRecognizer { diff --git a/Sources/UXKit/AppKit/UXGraphics-AppKit.swift b/Sources/UXKit/AppKit/UXGraphics-AppKit.swift index da49f22..4226f66 100644 --- a/Sources/UXKit/AppKit/UXGraphics-AppKit.swift +++ b/Sources/UXKit/AppKit/UXGraphics-AppKit.swift @@ -17,6 +17,8 @@ public let UXEdgeInsetsMake = NSEdgeInsetsMake public typealias UXImage = NSImage + public typealias UXEvent = NSEvent + public typealias UXTouch = NSTouch #if swift(>=4.0) public typealias UXEdgeInsets = NSEdgeInsets @@ -65,5 +67,81 @@ static var applicationIconImage: UXImage? { return UXImage(named: NSImage.applicationIconName) } + + /// Returns an image of the specified size, allowing the caller to provide a draw function that draws into the "current" graphics context. + /// - Parameters: + /// - size: The size of the image + /// - drawContent: A block responsible for drawing into the image. + /// - Returns: The image (which may be blank). + static func image(withSize size: CGSize, andContent drawContent: () -> Void) -> UXImage { + let resultImage = NSImage(size: size) + if let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(size.width), pixelsHigh: Int(size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0) { + resultImage.addRepresentation(rep) + NSGraphicsContext.saveGraphicsState() + NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep) + + drawContent() + + NSGraphicsContext.restoreGraphicsState() + } + + return resultImage + } } + +import class SpriteKit.SKScene + +public extension UXTouch { + + func location(inScene: SKScene) -> UXPoint { + return self.location(in: inScene.view) + } +} + +public extension NSBezierPath { + + /// CREDIT: https://gist.github.com/juliensagot/9749c3a1df28c38fb9f9 + /// A `CGPath` object representing the current `NSBezierPath`. + var cgPath: CGPath { + let path = CGMutablePath() + let points = UnsafeMutablePointer.allocate(capacity: 3) + + if elementCount > 0 { + for index in 0.. Int { + return self.numberOfRows + } } - public extension NSTableView { + + extension UXTableView { + open override func edit(withFrame rect: NSRect, editor textObj: NSText, delegate: Any?, event: NSEvent) { + textObj.becomeFirstResponder() + } +} + public extension UXTableView { /// UIKit compat method for `makeView(withIdentifier:owner:)`. This one /// passes `nil` as the owner. func dequeueReusableCell(withIdentifier identifier: String) - -> UXView? + -> UXTableViewCell? { return makeView(withIdentifier: UXUserInterfaceItemIdentifier(identifier), - owner: nil) + owner: nil) as? UXTableViewCell } /// UIKit compat method for `makeView(withIdentifier:owner:)`. This one @@ -102,7 +144,7 @@ /// on AppKit. /// Note: Raises a fatalError if the cell could not be constructed! func dequeueReusableCell(withIdentifier identifier: String, - for indexPath: IndexPath) -> UXView + for indexPath: IndexPath) -> UXTableViewCell { guard let v = dequeueReusableCell(withIdentifier: identifier) else { fatalError("could not construct cell for \(identifier)") @@ -111,4 +153,24 @@ } } + +public class UXCustomRowView: NSTableRowView { + + public override func drawSelection(in dirtyRect: NSRect) { + + if self.isSelected { + if #available(macOS 10.14, *) { + NSColor.selectedContentBackgroundColor.set() + } else { + // Fallback on earlier versions + NSColor.selectedMenuItemColor.set() + } + } else { + NSColor.clear.set() + } + + dirtyRect.fill() + } +} + #endif // os(macOS) diff --git a/Sources/UXKit/AppKit/UXView-AppKit.swift b/Sources/UXKit/AppKit/UXView-AppKit.swift index deee3a7..bce29f1 100644 --- a/Sources/UXKit/AppKit/UXView-AppKit.swift +++ b/Sources/UXKit/AppKit/UXView-AppKit.swift @@ -26,8 +26,9 @@ public typealias UXCheckBox = NSButton public typealias UXImageView = NSImageView public typealias UXSlider = NSSlider - - + public typealias UXAccessibility = NSAccessibility + public typealias UXAccessibilityElement = NSAccessibilityElement + // MARK: - UXUserInterfaceItemIdentification #if os(macOS) && swift(>=4.0) @@ -68,6 +69,64 @@ // maybe?) return CGPoint(x: NSMidX(frame), y: NSMidY(frame)) } + + var alpha: CGFloat { + get { + return self.alphaValue + } + set { + self.alphaValue = newValue + } + } + + func setSubViews(enabled: Bool) { + self.subviews.forEach { subView in + if subView.isKind(of: NSControl.self) { + (subView as! NSControl).isEnabled = enabled + } + + subView.setSubViews(enabled: enabled) + + subView.display() + } + } + + func isAnySubViewEnabled() -> Bool { + var result : Bool = false + + var iterator = self.subviews.enumerated().makeIterator() + + var current = iterator.next()?.element + + while current != nil && !result { + if current != nil { + if current!.isKind(of: NSControl.self) { + result = (current as! NSControl).isEnabled + } + + if !result { + result = current!.isAnySubViewEnabled() + + if !result { + current = iterator.next()?.element + } + } + } + } + + return result + } + + var isUserInteractionEnabled : Bool { + get { + return isAnySubViewEnabled() + } + + set { + setSubViews(enabled: newValue) + } + } + } public extension NSProgressIndicator { @@ -112,9 +171,77 @@ set { alignment = newValue } get { return alignment } } + + var text : String? { + get { + return self.stringValue + } + set { + if let nv = newValue { + self.stringValue = nv + } else { + self.stringValue = "" + } + } + } + + var placeholder : String? { + get { + return self.placeholderString + } + set { + if let nv = newValue { + self.placeholderString = nv + } else { + self.placeholderString = "" + } + } + } } + // provides a cross-compatible delegate protocol. +public protocol UXTextFieldDelegate : NSTextFieldDelegate { + func textField(_ textField: UXTextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool + + func textFieldDidBeginEditing(_ textField: UXTextField) + + func textFieldDidEndEditing(_ textField: UXTextField) + + func textFieldShouldReturn(_ textField: UXTextField) -> Bool + } + +open class VerticallyCenteredTextFieldCell: NSTextFieldCell { + + fileprivate var isEditingOrSelecting : Bool = false + + open override func drawingRect(forBounds rect: NSRect) -> NSRect { + let rect = super.drawingRect(forBounds: rect) + + if !isEditingOrSelecting { + let size = cellSize(forBounds: rect) + return NSRect(x: rect.minX, y: rect.minY + (rect.height - size.height) / 2, width: rect.width, height: size.height) + } + + return rect + } + + open override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) { + let aRect = self.drawingRect(forBounds: rect) + isEditingOrSelecting = true + super.select(withFrame: aRect, in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength) + isEditingOrSelecting = false + } + + open override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) { + let aRect = self.drawingRect(forBounds: rect) + isEditingOrSelecting = true + super.edit(withFrame: aRect, in: controlView, editor: textObj, delegate: delegate, event: event) + isEditingOrSelecting = false + } + +} + public extension UXSpinner { /// Use this instead of `isDisplayedWhenStopped` for UIKit compatibility. var hidesWhenStopped : Bool { @@ -141,4 +268,38 @@ } } + +public extension UXAccessibility { + + static func post(notification: UXAccessibility.Notification, + argument: Any) { + DispatchQueue.main.async { + if notification == .announcementRequested { + let userInfo = [ NSAccessibility.NotificationUserInfoKey.announcement : argument, NSAccessibility.NotificationUserInfoKey.priority : NSAccessibilityPriorityLevel.medium] + + if let window = NSApplication.shared.mainWindow { + NSAccessibility.post(element: window, notification: notification, userInfo: userInfo) + } + } else { + let userInfo : [ NSAccessibility.NotificationUserInfoKey : Any ] + + if let children = argument as? Array { + userInfo = [.uiElements : children] + } else { + userInfo = [.uiElements : [argument]] + } + + if let window = NSApplication.shared.mainWindow { + NSAccessibility.post(element: window, notification: notification, userInfo: userInfo) + } + } + } + } +} + +public extension NSAttributedString.Key { + static let accessibilitySpeechLanguage : NSAttributedString.Key = .accessibilityLanguage + +} + #endif // os(macOS) diff --git a/Sources/UXKit/Common/UXAlert.swift b/Sources/UXKit/Common/UXAlert.swift index c049e90..c85662e 100644 --- a/Sources/UXKit/Common/UXAlert.swift +++ b/Sources/UXKit/Common/UXAlert.swift @@ -11,10 +11,148 @@ public typealias UXAlert = NSAlert + +public extension UXAlert.Style { + + static let alert : UXAlert.Style = .warning +} + +/// A UIKit style AlertAction to provide code compatibility to the enclosing application. +/// Use this to add an 'action' to a UXAlert. +/// +public class UXAlertAction { + + /// The style of the action / button + public enum Style : Int { + case `default` = 0 + case cancel + case destructive + } + + /// Action style + var style : Style + + /// Action title. + var title : String? + + /// The handler block for the action. + var handler : ((UXAlertAction) -> Void)? + + /// These properties are used to allow the action to insert itself into the responder chain for when the + /// action is triggered. + /// + private var chainingButton : NSButton? + private var chainedTarget : AnyObject? + private var chainedSelector : Selector? + + /// Initialise the action with the supplied parameters. + /// - Parameters: + /// - title: the title for the action; this will be the text of the button (pre-localized) + /// - style: the style of the action; used to change the L&F of the button. + /// - handler: a block that will be called when the action is triggered by the alert.. + public init(title: String?, + style: UXAlertAction.Style, + handler: ((UXAlertAction) -> Void)? = nil) { + self.style = style + self.title = title + self.handler = handler + } + + /// A method that can be called by the alert when the associated button is pressed. + @objc func action(sender: AnyObject?) { + // If we actually have a handler, then call it. + if let handlerBlock = self.handler { + handlerBlock(self) + } + + // If there is a chained button, then call whatever action it was given by + // AppKit when the button was created. + // + if chainingButton != nil && + chainedTarget != nil && + chainedSelector != nil { + if let target = chainedTarget as? NSObject { + if target.responds(to: chainedSelector) { + target.perform(chainedSelector, with: sender) + } + } + } + } + + /// Inserts the action into the responder chain by first preserving whatever action AppKit + /// gave to the button when it was created, and then inserting this action. + /// - Parameter button: the button to be chained to. + func chainAction(toButton button: NSButton) { + // first preserve a reference to the button and it's current action. + self.chainingButton = button + self.chainedTarget = button.target + self.chainedSelector = button.action + + // now override the button action so that it triggers this action. + // + button.target = self + button.action = #selector(action) + } +} + +/// An extension to NSAlert that adds a layer of code compatibility for apps that need to work on both UIKit and AppKit. +public extension UXAlert { + + + /// Initialise a new UXAlert with the provided parameters. + /// - Parameters: + /// - title: a pre-localized title for the alert + /// - message: a pre-localized message for the alert + /// - preferredStyle: the preferred style of the alert + convenience init(title: String?, + message: String?, + preferredStyle: UXAlert.Style) { + self.init() + + if title != nil { + self.messageText = title! + } + + if message != nil { + self.informativeText = message! + } + + self.alertStyle = preferredStyle + } + + /// Adds a single UXAlertAction to the alert, presenting it as a button. Due to the way NSAlert works in + /// AppKit, it is recommended that the "default" action be added first. Destructive buttons should never + /// be added first as AppKit ignores some of the styling that would normally happen for destructive buttons + /// when they are also the "default" button. + /// - Parameter action: the action to be added. + func addAction(_ action: UXAlertAction) { + switch action.style { + case .default: + let button = self.addButton(withTitle: action.title!) + action.chainAction(toButton: button) + case .cancel: + let button = self.addButton(withTitle: action.title!) + action.chainAction(toButton: button) + case .destructive: + let button = self.addButton(withTitle: action.title!) + action.chainAction(toButton: button) + + if #available(macOS 11.0, *) { + button.hasDestructiveAction = true + } else { + if #available(macOS 10.14, *) { + button.contentTintColor = .red + } + } + } + } +} + #elseif os(iOS) import UIKit public typealias UXAlert = UIAlertController + public typealias UXAlertAction = UIAlertAction public extension UIAlertController { diff --git a/Sources/UXKit/Common/UXIndexPath.swift b/Sources/UXKit/Common/UXIndexPath.swift index f6bc0fb..71984a0 100644 --- a/Sources/UXKit/Common/UXIndexPath.swift +++ b/Sources/UXKit/Common/UXIndexPath.swift @@ -9,6 +9,16 @@ import Foundation #if swift(>=4.0) // Hm. It does seem to have it (produces ambiguities). But maybe not. import AppKit + public extension IndexPath { + var row : Int { + get { + return self.item + } + } + init(row: Int, section: Int) { + self.init(item: row, section: section) + } + } #else public extension IndexPath { diff --git a/Sources/UXKit/Common/UXTextView.swift b/Sources/UXKit/Common/UXTextView.swift index f50305d..75a5f28 100644 --- a/Sources/UXKit/Common/UXTextView.swift +++ b/Sources/UXKit/Common/UXTextView.swift @@ -13,10 +13,16 @@ import class UIKit.NSTextContainer import struct UIKit.NSTextStorageEditActions import class UIKit.UITextView + import enum UIKit.NSTextAlignment + import class UIKit.NSMutableParagraphStyle + import class UIKit.NSStringDrawingContext public typealias NSTextStorage = UIKit.NSTextStorage public typealias NSLayoutManager = UIKit.NSLayoutManager public typealias NSTextContainer = UIKit.NSTextContainer + public typealias NSTextAlignment = UIKit.NSTextAlignment + public typealias NSMutableParagraphStyle = UIKit.NSMutableParagraphStyle + public typealias NSStringDrawingContext = UIKit.NSStringDrawingContext public typealias NSTextStorageEditActions = UIKit.NSTextStorage.EditActions @@ -48,10 +54,16 @@ import class AppKit.NSTextContainer import struct AppKit.NSTextStorageEditActions import class AppKit.NSTextView + import enum AppKit.NSTextAlignment + import class AppKit.NSMutableParagraphStyle + import class AppKit.NSStringDrawingContext public typealias NSTextStorage = AppKit.NSTextStorage public typealias NSLayoutManager = AppKit.NSLayoutManager public typealias NSTextContainer = AppKit.NSTextContainer + public typealias NSTextAlignment = AppKit.NSTextAlignment + public typealias NSMutableParagraphStyle = AppKit.NSMutableParagraphStyle + public typealias NSStringDrawingContext = AppKit.NSStringDrawingContext @available(macOS 10.11, *) public typealias NSTextStorageEditActions = AppKit.NSTextStorageEditActions diff --git a/Sources/UXKit/Common/UXViewController.swift b/Sources/UXKit/Common/UXViewController.swift index b3db349..f608550 100644 --- a/Sources/UXKit/Common/UXViewController.swift +++ b/Sources/UXKit/Common/UXViewController.swift @@ -79,4 +79,14 @@ public var uxChildren : [ UXViewController ] { return children } public func uxRemoveFromParent() { removeFromParent() } public var uxParent : UXViewController? { return parent } + +#if os(macOS) + public func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { + self.dismiss(self) + } + + public func present(_ viewControllerToPresent: UXViewController, animated flag: Bool, completion: (() -> Void)? = nil) { + self.presentAsModalWindow(viewControllerToPresent) + } +#endif } diff --git a/Sources/UXKit/UIKit/UXFont-UIKit.swift b/Sources/UXKit/UIKit/UXFont-UIKit.swift index 65bb73c..6341be1 100644 --- a/Sources/UXKit/UIKit/UXFont-UIKit.swift +++ b/Sources/UXKit/UIKit/UXFont-UIKit.swift @@ -20,17 +20,27 @@ * `UIFont.monospacedSystemFont()`. */ static func userFixedPitchFont(ofSize size: CGFloat) -> UXFont? { - if #available(iOS 13.0, *) { - #if true - return UIFont(name: "Menlo-Regular", size: size) - ?? UIFont.monospacedSystemFont(ofSize: size, weight: .regular) - #else - return UIFont.monospacedSystemFont(ofSize: size, weight: .regular) - #endif - } - else { - return nil - } +#if os(iOS) + if #available(iOS 13.0, *) { + return UIFont(name: "Menlo-Regular", size: size) + ?? UIFont.monospacedSystemFont(ofSize: size, weight: .regular) + } else { + return UIFont(name: "Menlo-Regular", size: size) + } +#endif + +#if os(tvOS) + if #available(tvOS 13.0, *) { + return UIFont(name: "Menlo-Regular", size: size) + ?? UIFont.monospacedSystemFont(ofSize: size, weight: .regular) + } else { + return UIFont(name: "Menlo-Regular", size: size) + } +#endif + +#if os(visionOS) +return UIFont(name: "Menlo-Regular", size: size) +#endif } } #endif // !os(macOS) diff --git a/Sources/UXKit/UIKit/UXGestures-UIKit.swift b/Sources/UXKit/UIKit/UXGestures-UIKit.swift index 899dccd..51e475a 100644 --- a/Sources/UXKit/UIKit/UXGestures-UIKit.swift +++ b/Sources/UXKit/UIKit/UXGestures-UIKit.swift @@ -7,6 +7,7 @@ import UIKit public typealias UXGestureRecognizer = UIGestureRecognizer + public typealias UXGestureRecognizerDelegate = UIGestureRecognizerDelegate public typealias UXPanGestureRecognizer = UIPanGestureRecognizer public typealias UXTapGestureRecognizer = UITapGestureRecognizer #if !os(tvOS) diff --git a/Sources/UXKit/UIKit/UXGraphics-UIKit.swift b/Sources/UXKit/UIKit/UXGraphics-UIKit.swift index 99a932c..6eebe73 100644 --- a/Sources/UXKit/UIKit/UXGraphics-UIKit.swift +++ b/Sources/UXKit/UIKit/UXGraphics-UIKit.swift @@ -15,6 +15,9 @@ public typealias UXRect = CGRect public typealias UXPoint = CGPoint public typealias UXSize = CGSize + public typealias UXRectCorner = UIRectCorner + public typealias UXEvent = UIEvent + public typealias UXTouch = UITouch public typealias UXImage = UIImage @@ -33,8 +36,19 @@ /// macOS compat, using `.label` on iOS 13+ (dynamic), `.black` before. @inlinable static var textColor : UXColor { - if #available(iOS 13, *) { return UXColor.label } - else { return UXColor.black } +#if os(iOS) + if #available(iOS 13, *) { return UXColor.label } + else { return UXColor.black } +#endif + +#if os(tvOS) + if #available(tvOS 13, *) { return UXColor.label } + else { return UXColor.black } +#endif + + #if os(visionOS) + return UXColor.black + #endif } } @@ -57,6 +71,22 @@ as? [ String ])?.first else { return nil } return UXImage(named: icon) } + + /// Returns an image of the specified size, allowing the caller to provide a draw function that draws into the "current" graphics context. + /// - Parameters: + /// - size: The size of the image + /// - drawContent: A block responsible for drawing into the image. + /// - Returns: The image (which may be blank). + static func image(withSize size: CGSize, andContent drawContent: () -> Void) -> UXImage { + UIGraphicsBeginImageContextWithOptions(size, false, 1.0); + + drawContent() + + let result = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return result! + } } public extension Bundle { diff --git a/Sources/UXKit/UIKit/UXTableView-UIKit.swift b/Sources/UXKit/UIKit/UXTableView-UIKit.swift index 12d7f89..8a50e4d 100644 --- a/Sources/UXKit/UIKit/UXTableView-UIKit.swift +++ b/Sources/UXKit/UIKit/UXTableView-UIKit.swift @@ -33,6 +33,9 @@ */ public typealias UXTableViewCell = UITableViewCell // same on iOS + public typealias UXTableViewDelegate = UITableViewDelegate + public typealias UXTableViewDataSource = UITableViewDataSource + public typealias UXTableViewCellStyle = UITableViewCell.CellStyle public extension UITableView.RowAnimation { static var effectFade = UITableView.RowAnimation.fade diff --git a/Sources/UXKit/UIKit/UXView-UIKit.swift b/Sources/UXKit/UIKit/UXView-UIKit.swift index f7bb779..d8e0519 100644 --- a/Sources/UXKit/UIKit/UXView-UIKit.swift +++ b/Sources/UXKit/UIKit/UXView-UIKit.swift @@ -4,96 +4,103 @@ // Copyright © 2016-2021 ZeeZide GmbH. All rights reserved. // #if !os(macOS) - import UIKit +import UIKit - public typealias UXWindow = UIWindow - public typealias UXView = UIView - public typealias UXResponder = UIResponder - public typealias UXControl = UIControl - public typealias UXLabel = UILabel - public typealias UXTextField = UITextField - public typealias UXSecureTextField = UITextField - public typealias UXScrollView = UIScrollView - public typealias UXCollectionView = UICollectionView - public typealias UXSearchField = UISearchBar // TBD - public typealias UXSpinner = UIActivityIndicatorView - public typealias UXProgressBar = UIProgressView - public typealias UXButton = UIButton - public typealias UXTextView = UITextView - public typealias UXTextViewDelegate = UITextViewDelegate - // public typealias UXPopUp = TODO - public typealias UXStackView = UIStackView - public typealias UXImageView = UIImageView - #if !os(tvOS) - public typealias UXCheckBox = UISwitch - public typealias UXSlider = UISlider - #endif - - - // MARK: - UXUserInterfaceItemIdentification - - public typealias UXUserInterfaceItemIdentifier = String - // FIXME: maybe we should change it to the new Raw type in AppKit Swift 4 - - @objc public protocol UXUserInterfaceItemIdentification { +public typealias UXWindow = UIWindow +public typealias UXView = UIView +public typealias UXResponder = UIResponder +public typealias UXControl = UIControl +public typealias UXLabel = UILabel +public typealias UXTextField = UITextField +public typealias UXSecureTextField = UITextField +public typealias UXScrollView = UIScrollView +public typealias UXCollectionView = UICollectionView +public typealias UXSearchField = UISearchBar // TBD +public typealias UXSpinner = UIActivityIndicatorView +public typealias UXProgressBar = UIProgressView +public typealias UXButton = UIButton +public typealias UXTextView = UITextView +public typealias UXTextViewDelegate = UITextViewDelegate +// public typealias UXPopUp = TODO +public typealias UXStackView = UIStackView +public typealias UXImageView = UIImageView +#if !os(tvOS) +public typealias UXCheckBox = UISwitch +public typealias UXSlider = UISlider +#endif + +public typealias UXAccessibility = UIAccessibility +public typealias UXAccessibilityElement = UIAccessibilityElement +public typealias UXTextFieldDelegate = UITextFieldDelegate + +// MARK: - UXUserInterfaceItemIdentification + +public typealias UXUserInterfaceItemIdentifier = String +// FIXME: maybe we should change it to the new Raw type in AppKit Swift 4 + +@objc public protocol UXUserInterfaceItemIdentification { var identifier: UXUserInterfaceItemIdentifier? { get set } - } - - - // MARK: - NSView Compatibility - - public extension UIActivityIndicatorView { +} + +public extension UXAccessibility.Notification { + static let valueChanged: UXAccessibility.Notification = .layoutChanged + static let announcementRequested: UXAccessibility.Notification = .announcement +} + +// MARK: - NSView Compatibility + +public extension UIActivityIndicatorView { /// Use this instead of `start[stop]Animating` for AppKit compatibility. var isSpinning : Bool { - set { - guard newValue != isAnimating else { return } - if newValue { startAnimating() } - else { stopAnimating() } - } - get { - return isAnimating - } + set { + guard newValue != isAnimating else { return } + if newValue { startAnimating() } + else { stopAnimating() } + } + get { + return isAnimating + } } /// AppKit compatibility. Prefer: `hidesWhenStopped`. /// Note: It's the other way around! var isDisplayedWhenStopped : Bool { - set { hidesWhenStopped = !newValue } - get { return !hidesWhenStopped } + set { hidesWhenStopped = !newValue } + get { return !hidesWhenStopped } } - } - - public extension UIButton { +} + +public extension UIButton { var title : String? { - set { setTitle(newValue, for: .normal) } - get { return title(for: .normal) } + set { setTitle(newValue, for: .normal) } + get { return title(for: .normal) } } - } +} #if !os(tvOS) - public extension UISlider { +public extension UISlider { // UISlider base value is a `Float` var intValue : Int32 { // yeah, it is Int32 in Cocoa :-) - set { value = Float(newValue) } - get { return Int32(value) } + set { value = Float(newValue) } + get { return Int32(value) } } - } +} #endif - public extension UXView { +public extension UXView { func inOwnContext(execute: () -> ()) { - let context = UIGraphicsGetCurrentContext() - context?.saveGState() - defer { context?.restoreGState() } - - execute() + let context = UIGraphicsGetCurrentContext() + context?.saveGState() + defer { context?.restoreGState() } + + execute() } - - } + +} #endif // !os(macOS) diff --git a/UXKit.xcodeproj/project.pbxproj b/UXKit.xcodeproj/project.pbxproj index 1feb128..934e1d9 100644 --- a/UXKit.xcodeproj/project.pbxproj +++ b/UXKit.xcodeproj/project.pbxproj @@ -22,6 +22,24 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + D037E3F727D6278700892CF0 /* UXTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8BF4DC4247025F20055AA53 /* UXTextView.swift */; }; + D037E3F827D6278700892CF0 /* UXGestureActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A937061FD7322800F180F8 /* UXGestureActions.swift */; }; + D037E3F927D6278700892CF0 /* UXObjectPresentingType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2511FBB326800C1063B /* UXObjectPresentingType.swift */; }; + D037E3FA27D6278700892CF0 /* UXObjectControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2501FBB326800C1063B /* UXObjectControl.swift */; }; + D037E3FB27D6278700892CF0 /* UXPasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2521FBB326800C1063B /* UXPasteboard.swift */; }; + D037E3FC27D6278700892CF0 /* UXViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2531FBB326800C1063B /* UXViewController.swift */; }; + D037E3FD27D6278700892CF0 /* UXViewType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82E9D41223A953A005A52AE /* UXViewType.swift */; }; + D037E3FE27D6278700892CF0 /* UXAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8080ECE234E43060022D71A /* UXAlert.swift */; }; + D037E3FF27D6278700892CF0 /* UXIndexPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B24F1FBB326800C1063B /* UXIndexPath.swift */; }; + D037E40027D6279200892CF0 /* UXCollectionView-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2551FBB326800C1063B /* UXCollectionView-UIKit.swift */; }; + D037E40127D6279200892CF0 /* UXTargetAction-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B25B1FBB326800C1063B /* UXTargetAction-UIKit.swift */; }; + D037E40227D6279200892CF0 /* NSSound.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83935312698823E00272DA7 /* NSSound.swift */; }; + D037E40327D6279200892CF0 /* UXFont-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2561FBB326800C1063B /* UXFont-UIKit.swift */; }; + D037E40427D6279200892CF0 /* UXTableView-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B25A1FBB326800C1063B /* UXTableView-UIKit.swift */; }; + D037E40527D6279200892CF0 /* UXView-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B25C1FBB326800C1063B /* UXView-UIKit.swift */; }; + D037E40627D6279200892CF0 /* UXGestures-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2571FBB326800C1063B /* UXGestures-UIKit.swift */; }; + D037E40727D6279200892CF0 /* UXLayout-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2591FBB326800C1063B /* UXLayout-UIKit.swift */; }; + D037E40827D6279200892CF0 /* UXGraphics-UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A9B2581FBB326800C1063B /* UXGraphics-UIKit.swift */; }; E8080ECF234E43060022D71A /* UXAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8080ECE234E43060022D71A /* UXAlert.swift */; }; E8080ED0234E43060022D71A /* UXAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8080ECE234E43060022D71A /* UXAlert.swift */; }; E82E9D42223A953A005A52AE /* UXViewType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82E9D41223A953A005A52AE /* UXViewType.swift */; }; @@ -78,6 +96,15 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + D037E3EE27D6270B00892CF0 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; E8A9B27E1FBB351D00C1063B /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -90,6 +117,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + D037E3F027D6270B00892CF0 /* libUXKit-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libUXKit-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; E8080ECE234E43060022D71A /* UXAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UXAlert.swift; sourceTree = ""; }; E82E9D41223A953A005A52AE /* UXViewType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UXViewType.swift; sourceTree = ""; }; E83935312698823E00272DA7 /* NSSound.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSSound.swift; sourceTree = ""; }; @@ -131,6 +159,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + D037E3ED27D6270B00892CF0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; E8A9B2331FBB318700C1063B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -178,6 +213,7 @@ children = ( E8A9B2361FBB318800C1063B /* libUXKit-AppKit.a */, E8A9B2801FBB351D00C1063B /* libUXKit-UIKit.a */, + D037E3F027D6270B00892CF0 /* libUXKit-tvOS.a */, ); name = Products; sourceTree = ""; @@ -261,6 +297,23 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + D037E3EF27D6270B00892CF0 /* UXKit-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = D037E3F627D6270B00892CF0 /* Build configuration list for PBXNativeTarget "UXKit-tvOS" */; + buildPhases = ( + D037E3EC27D6270B00892CF0 /* Sources */, + D037E3ED27D6270B00892CF0 /* Frameworks */, + D037E3EE27D6270B00892CF0 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "UXKit-tvOS"; + productName = "UXKit-tvOS"; + productReference = D037E3F027D6270B00892CF0 /* libUXKit-tvOS.a */; + productType = "com.apple.product-type.library.static"; + }; E8A9B2351FBB318700C1063B /* UXKit-AppKit */ = { isa = PBXNativeTarget; buildConfigurationList = E8A9B23F1FBB318800C1063B /* Build configuration list for PBXNativeTarget "UXKit-AppKit" */; @@ -305,6 +358,10 @@ LastUpgradeCheck = 1500; ORGANIZATIONNAME = "ZeeZide GmbH"; TargetAttributes = { + D037E3EF27D6270B00892CF0 = { + CreatedOnToolsVersion = 13.2.1; + ProvisioningStyle = Automatic; + }; E85CBD30233F736A0065D1DB = { CreatedOnToolsVersion = 11.1; ProvisioningStyle = Automatic; @@ -336,12 +393,38 @@ targets = ( E8A9B2351FBB318700C1063B /* UXKit-AppKit */, E8A9B27F1FBB351D00C1063B /* UXKit-UIKit */, + D037E3EF27D6270B00892CF0 /* UXKit-tvOS */, E85CBD30233F736A0065D1DB /* UXKit-AllPlatforms */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ + D037E3EC27D6270B00892CF0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D037E3FF27D6278700892CF0 /* UXIndexPath.swift in Sources */, + D037E3FC27D6278700892CF0 /* UXViewController.swift in Sources */, + D037E40027D6279200892CF0 /* UXCollectionView-UIKit.swift in Sources */, + D037E3FA27D6278700892CF0 /* UXObjectControl.swift in Sources */, + D037E3F927D6278700892CF0 /* UXObjectPresentingType.swift in Sources */, + D037E3F727D6278700892CF0 /* UXTextView.swift in Sources */, + D037E40127D6279200892CF0 /* UXTargetAction-UIKit.swift in Sources */, + D037E40727D6279200892CF0 /* UXLayout-UIKit.swift in Sources */, + D037E3FB27D6278700892CF0 /* UXPasteboard.swift in Sources */, + D037E40527D6279200892CF0 /* UXView-UIKit.swift in Sources */, + D037E40227D6279200892CF0 /* NSSound.swift in Sources */, + D037E40827D6279200892CF0 /* UXGraphics-UIKit.swift in Sources */, + D037E3FD27D6278700892CF0 /* UXViewType.swift in Sources */, + D037E40427D6279200892CF0 /* UXTableView-UIKit.swift in Sources */, + D037E40327D6279200892CF0 /* UXFont-UIKit.swift in Sources */, + D037E3F827D6278700892CF0 /* UXGestureActions.swift in Sources */, + D037E3FE27D6278700892CF0 /* UXAlert.swift in Sources */, + D037E40627D6279200892CF0 /* UXGestures-UIKit.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; E8A9B2321FBB318700C1063B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -408,19 +491,158 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + D037E3F427D6270B00892CF0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = YTQG85D588; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_MODULE_NAME = UXKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 12.0; + }; + name = Debug; + }; + D037E3F527D6270B00892CF0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = YTQG85D588; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_MODULE_NAME = UXKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 12.0; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; E85CBD31233F736A0065D1DB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; + SUPPORTS_MACCATALYST = YES; }; name = Debug; }; E85CBD32233F736A0065D1DB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos"; + SUPPORTS_MACCATALYST = YES; }; name = Release; }; @@ -428,6 +650,10 @@ isa = XCBuildConfiguration; baseConfigurationReference = E8460D771FBF12D2002CDC28 /* Debug.xcconfig */; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + MACOSX_DEPLOYMENT_TARGET = 10.13; + TVOS_DEPLOYMENT_TARGET = 13.0; + WATCHOS_DEPLOYMENT_TARGET = 8.3; }; name = Debug; }; @@ -435,6 +661,10 @@ isa = XCBuildConfiguration; baseConfigurationReference = E8460D7A1FBF12D2002CDC28 /* Release.xcconfig */; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + MACOSX_DEPLOYMENT_TARGET = 10.13; + TVOS_DEPLOYMENT_TARGET = 13.0; + WATCHOS_DEPLOYMENT_TARGET = 8.3; }; name = Release; }; @@ -443,8 +673,11 @@ baseConfigurationReference = E8460D781FBF12D2002CDC28 /* MacStaticLib.xcconfig */; buildSettings = { EXECUTABLE_PREFIX = lib; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_MODULE_NAME = UXKit; PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; @@ -453,8 +686,11 @@ baseConfigurationReference = E8460D781FBF12D2002CDC28 /* MacStaticLib.xcconfig */; buildSettings = { EXECUTABLE_PREFIX = lib; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_MODULE_NAME = UXKit; PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Release; }; @@ -462,11 +698,13 @@ isa = XCBuildConfiguration; baseConfigurationReference = E8460D791FBF12D2002CDC28 /* MobileStaticLib.xcconfig */; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 12.0; PRODUCT_MODULE_NAME = UXKit; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; }; @@ -474,11 +712,13 @@ isa = XCBuildConfiguration; baseConfigurationReference = E8460D791FBF12D2002CDC28 /* MobileStaticLib.xcconfig */; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 12.0; PRODUCT_MODULE_NAME = UXKit; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -486,6 +726,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + D037E3F627D6270B00892CF0 /* Build configuration list for PBXNativeTarget "UXKit-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D037E3F427D6270B00892CF0 /* Debug */, + D037E3F527D6270B00892CF0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; E85CBD33233F736A0065D1DB /* Build configuration list for PBXAggregateTarget "UXKit-AllPlatforms" */ = { isa = XCConfigurationList; buildConfigurations = (