From 4887a50c485ca0b2b57377aa885b19c943b3e0cd Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 29 Nov 2018 14:29:27 -0600 Subject: [PATCH 001/139] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index d5a36edc..6b99aaa1 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,14 @@ [![Platform](https://img.shields.io/cocoapods/p/SwiftMessages.svg?style=flat)](http://cocoadocs.org/docsets/SwiftMessages) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +## πŸ”₯ SwiftAutoLayout πŸ”₯ + +Check out our new library, [SwiftAutoLayout](https://github.com/SwiftKickMobile/SwiftAutoLayout)! SwiftAutoLayout helps you write AutoLayout constraints as consisely, Swiftly, and as natively as possible. Constrain `UIView` and `UILayoutGuide`s interchangeably with a familiar syntax named to match their native properties. This library purposefuly minimizes the repetitive code of defining view hierarchies and building constraints while maximizing constraint flexibility via optional parameters. + +

+ +

+ ## πŸ”₯ View Controllers πŸ”₯ SwiftMessages can now present view controllers using the `SwiftMessagesSegue` custom modal segue! From f8d4d4b97271f9807fb6f14c494c7c89f2476db3 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 29 Nov 2018 14:31:39 -0600 Subject: [PATCH 002/139] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b99aaa1..7c598beb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ ## πŸ”₯ SwiftAutoLayout πŸ”₯ -Check out our new library, [SwiftAutoLayout](https://github.com/SwiftKickMobile/SwiftAutoLayout)! SwiftAutoLayout helps you write AutoLayout constraints as consisely, Swiftly, and as natively as possible. Constrain `UIView` and `UILayoutGuide`s interchangeably with a familiar syntax named to match their native properties. This library purposefuly minimizes the repetitive code of defining view hierarchies and building constraints while maximizing constraint flexibility via optional parameters. +Check out our new repo, [SwiftAutoLayout](https://github.com/SwiftKickMobile/SwiftAutoLayout)! + +SwiftAutoLayout helps you write AutoLayout constraints as consisely, Swiftly, and as natively as possible. Constrain `UIView` and `UILayoutGuide`s interchangeably with a familiar syntax named to match their native properties. This library purposefuly minimizes the repetitive code of defining view hierarchies and building constraints while maximizing constraint flexibility via optional parameters.

From b7dfd578982355dd126df0e5d674998352b5e327 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Wed, 26 Dec 2018 17:11:34 -0600 Subject: [PATCH 003/139] Add event listeners to SwiftMessagesSegue --- CHANGELOG.md | 6 ++++ README.md | 38 ++++++++------------- SwiftMessages.podspec | 2 +- SwiftMessages/SwiftMessagesSegue.swift | 46 +++++++++++++++----------- 4 files changed, 47 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afacc7b5..c4e7a38d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 6.0.2 + +### Features + +* #262 Add event listeners to `SwiftMessagesSegue`. + ## 6.0.1 ### Features diff --git a/README.md b/README.md index 7c598beb..7ec17686 100644 --- a/README.md +++ b/README.md @@ -6,30 +6,6 @@ [![Platform](https://img.shields.io/cocoapods/p/SwiftMessages.svg?style=flat)](http://cocoadocs.org/docsets/SwiftMessages) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) -## πŸ”₯ SwiftAutoLayout πŸ”₯ - -Check out our new repo, [SwiftAutoLayout](https://github.com/SwiftKickMobile/SwiftAutoLayout)! - -SwiftAutoLayout helps you write AutoLayout constraints as consisely, Swiftly, and as natively as possible. Constrain `UIView` and `UILayoutGuide`s interchangeably with a familiar syntax named to match their native properties. This library purposefuly minimizes the repetitive code of defining view hierarchies and building constraints while maximizing constraint flexibility via optional parameters. - -

- -

- -## πŸ”₯ View Controllers πŸ”₯ - -SwiftMessages can now present view controllers using the `SwiftMessagesSegue` custom modal segue! - -

- -

- -[`SwiftMessagesSegue`](./SwiftMessages/SwiftMessagesSegue.swift) is a subclass of `UIStoryboardSegue` that integrates directly into Interface Builder as a custom modal segue, enabling view controllers to take advantage of SwiftMessages layouts, animations and more. `SwiftMessagesSegue` works with any UIKIt project β€” storyboards are not required. Refer to the View Controllers readme below for more information. - -#### [View Controllers Readme](./ViewControllers.md) - -And check out our blog post [Elegant Custom UIViewController Transitioning](http://www.swiftkickmobile.com/elegant-custom-uiviewcontroller-transitioning-uiviewcontrollertransitioningdelegate-uiviewcontrolleranimatedtransitioning/) to learn a great technique you can use to build your own custom segues that utilize `UIViewControllerTransitioningDelegate` and `UIViewControllerAnimatedTransitioning`. -

@@ -56,6 +32,20 @@ Try exploring [the demo app via appetize.io](http://goo.gl/KXw4nD) to get a feel

+## View Controllers + +SwiftMessages can present view controllers using the `SwiftMessagesSegue` custom modal segue! + +

+ +

+ +[`SwiftMessagesSegue`](./SwiftMessages/SwiftMessagesSegue.swift) is a subclass of `UIStoryboardSegue` that integrates directly into Interface Builder as a custom modal segue, enabling view controllers to take advantage of SwiftMessages layouts, animations and more. `SwiftMessagesSegue` works with any UIKIt project β€” storyboards are not required. Refer to the View Controllers readme below for more information. + +#### [View Controllers Readme](./ViewControllers.md) + +And check out our blog post [Elegant Custom UIViewController Transitioning](http://www.swiftkickmobile.com/elegant-custom-uiviewcontroller-transitioning-uiviewcontrollertransitioningdelegate-uiviewcontrolleranimatedtransitioning/) to learn a great technique you can use to build your own custom segues that utilize `UIViewControllerTransitioningDelegate` and `UIViewControllerAnimatedTransitioning`. + ## Installation ### CocoaPods diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index bb06a74f..a471feb7 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '6.0.1' + spec.version = '6.0.2' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index 431e9947..9e3c56f0 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -109,6 +109,32 @@ open class SwiftMessagesSegue: UIStoryboardSegue { case backgroundVertical } + /// The presentation style to use. See the SwiftMessages.PresentationStyle for details. + public var presentationStyle: SwiftMessages.PresentationStyle { + get { return messenger.defaultConfig.presentationStyle } + set { messenger.defaultConfig.presentationStyle = newValue } + } + + /// The dim mode to use. See the SwiftMessages.DimMode for details. + public var dimMode: SwiftMessages.DimMode { + get { return messenger.defaultConfig.dimMode} + set { messenger.defaultConfig.dimMode = newValue } + } + + /// Specifies whether or not the interactive pan-to-hide gesture is enabled + /// on the message view. The default value is `true`, but may not be appropriate + /// for view controllers that use swipe or pan gestures. + public var interactiveHide: Bool { + get { return messenger.defaultConfig.interactiveHide } + set { messenger.defaultConfig.interactiveHide = newValue } + } + + /// Specifies an optional array of event listeners. + public var eventListeners: [SwiftMessages.EventListener] { + get { return messenger.defaultConfig.eventListeners } + set { messenger.defaultConfig.eventListeners = newValue } + } + /** The view that is passed to `SwiftMessages.show(config:view:)` during presentation. The view controller's view is installed into `containerView`, which is itself installed @@ -132,26 +158,6 @@ open class SwiftMessagesSegue: UIStoryboardSegue { */ public var containment: Containment = .content - /// The presentation style to use. See the SwiftMessages.PresentationStyle for details. - public var presentationStyle: SwiftMessages.PresentationStyle { - get { return messenger.defaultConfig.presentationStyle } - set { messenger.defaultConfig.presentationStyle = newValue } - } - - /// The dim mode to use. See the SwiftMessages.DimMode for details. - public var dimMode: SwiftMessages.DimMode { - get { return messenger.defaultConfig.dimMode} - set { messenger.defaultConfig.dimMode = newValue } - } - - /// Specifies whether or not the interactive pan-to-hide gesture is enabled - /// on the message view. The default value is `true`, but may not be appropriate - /// for view controllers that use swipe or pan gestures. - public var interactiveHide: Bool { - get { return messenger.defaultConfig.interactiveHide } - set { messenger.defaultConfig.interactiveHide = newValue } - } - private var messenger = SwiftMessages() private var selfRetainer: SwiftMessagesSegue? = nil private lazy var hider = { return TransitioningDismisser(segue: self) }() From 65b51e2ec80a596c73b5c2972f8aae83ca2222c1 Mon Sep 17 00:00:00 2001 From: Misery Lee Date: Tue, 1 Jan 2019 01:21:59 +0800 Subject: [PATCH 004/139] fixed #155 Message never hides after segue (#269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed #115 Message never hides after segue ```weak current``` has been released, that makes hide function not working. πŸ€”But why does it release, maybe a deeper learning is required. * Prevent orphaned messages --- SwiftMessages/SwiftMessages.swift | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index 115cd543..35650228 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -571,17 +571,16 @@ open class SwiftMessages { queue = queue.filter { $0.id != id } delays.ids.remove(id) } - + fileprivate func hideCurrent() { guard let current = _current, !current.isHiding else { return } let delay = current.delayHide ?? 0 - DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self, weak current] in - guard let strongCurrent = current else { return } - strongCurrent.hide { (completed) in - guard completed, let strongSelf = self, let strongCurrent = current else { return } + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in + current.hide { (completed) in + guard completed, let strongSelf = self else { return } strongSelf.messageQueue.sync { - guard strongSelf._current === strongCurrent else { return } - strongSelf.counts[strongCurrent.id] = nil + guard strongSelf._current === current else { return } + strongSelf.counts[current.id] = nil strongSelf._current = nil } } @@ -595,14 +594,18 @@ open class SwiftMessages { autohideToken = current if let pauseDuration = current.pauseDuration { let delayTime = DispatchTime.now() + pauseDuration - messageQueue.asyncAfter(deadline: delayTime, execute: { [weak self, weak current] in - guard let strongSelf = self, let current = current else { return } + messageQueue.asyncAfter(deadline: delayTime, execute: { // Make sure we've still got a green light to auto-hide. - if strongSelf.autohideToken !== current { return } - strongSelf.internalHide(id: current.id) + if self.autohideToken !== current { return } + self.internalHide(id: current.id) }) } } + + deinit { + // Prevent orphaned messages + hideCurrent() + } } /* From 2e92138998ade55a3cbe8a2778c9ae894fc9f92c Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Wed, 2 Jan 2019 10:56:00 -0600 Subject: [PATCH 005/139] Update ViewControllers.md --- ViewControllers.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ViewControllers.md b/ViewControllers.md index f5a525ac..561086ee 100644 --- a/ViewControllers.md +++ b/ViewControllers.md @@ -107,4 +107,14 @@ The view controller's view is a direct subview of `containerView`, an instance o segue.containerView.cornerRadius = 20 ```` +### Height + +SwiftMessages relies on Auto Layout to determine the height the view controller's view. + However, some view controllers, such as `UINavigationController` have zero Auto Layout height. + There are a few ways to specify the height of these view controllers: +1. Add an explicit height constraint to the view controller's view. +2. Set the view controller's `preferredContentSize` ("Use Preferred Explicit Size" in Interface Builder's + attribute inspector). Note that `preferredContentSize.width` is ignored and can be set to zero. +3. Set `SwiftMessagesSegue.messageView.backgroundHeight`. + See [`SwiftMessagesSegue`](./SwiftMessages/SwiftMessagesSegue.swift) for additional documentation and technical details. From 484ef7302012dd1f221992ebd50c10e27601673d Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Wed, 2 Jan 2019 13:15:19 -0600 Subject: [PATCH 006/139] Update documentation about view controller height --- SwiftMessages/SwiftMessagesSegue.swift | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index 9e3c56f0..546f54f8 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -42,12 +42,13 @@ import UIKit utilize some SwiftMessages features. This view can be accessed and configured via the `SwiftMessagesSegue.messageView` property. For example, you may configure a default drop shadow by calling `segue.messageView.configureDropShadow()`. - 2. SwiftMessages relies on a view's `intrinsicContentSize` to determine the height of a message. - However, some view controllers' views does not define a good `intrinsicContentSize` - (`UINavigationController` is a common example). For these cases, there are a couple of ways - to specify the preferred height. First, you may set the `preferredContentSize` on the destination - view controller (available as "Use Preferred Explicit Size" in IB's attribute inspector). Second, - you may set `SwiftMessagesSegue.messageView.backgroundHeight`. + 2. SwiftMessages relies on Auto Layout to determine the height the view controller's view. + However, some view controllers, such as `UINavigationController` have zero Auto Layout height. + There are a few ways to specify the height these view controllers: + 1. Add an explicit height constraint to the view controller's view. + 2. Set the view controller's `preferredContentSize` ("Use Preferred Explicit Size" in Interface Builder's + attribute inspector). Note that `preferredContentSize.width` is ignored and can be set to zero. + 3. Set `SwiftMessagesSegue.messageView.backgroundHeight`. See the "View Controllers" selection in the Demo app for examples. */ From d1158b61029f0710dd917ca0f315ac409a7658c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=AC=EC=84=B1?= Date: Sun, 6 Jan 2019 07:36:20 +0900 Subject: [PATCH 007/139] add duration (#272) --- SwiftMessages/SwiftMessagesSegue.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index 546f54f8..225d6863 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -121,6 +121,12 @@ open class SwiftMessagesSegue: UIStoryboardSegue { get { return messenger.defaultConfig.dimMode} set { messenger.defaultConfig.dimMode = newValue } } + + // duration + public var duration: SwiftMessages.Duration { + get { return messenger.defaultConfig.duration} + set { messenger.defaultConfig.duration = newValue } + } /// Specifies whether or not the interactive pan-to-hide gesture is enabled /// on the message view. The default value is `true`, but may not be appropriate From b9ad985245fa64c12f333da6cefee5e1a09f5bf9 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 21 Jan 2019 11:01:57 -0600 Subject: [PATCH 008/139] Add ability to hide message without animation --- CHANGELOG.md | 7 +++++++ Demo/Demo/ExploreViewController.swift | 2 +- SwiftMessages/Presenter.swift | 11 +++++++++-- SwiftMessages/SwiftMessages.swift | 19 +++++++++++-------- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4e7a38d..770d7f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log All notable changes to this project will be documented in this file. +## 6.0.3 + +### Features + +* #276 Add ability to hide message without animation +* #272 Add duration for `SwiftMessagesSegue` + ## 6.0.2 ### Features diff --git a/Demo/Demo/ExploreViewController.swift b/Demo/Demo/ExploreViewController.swift index d8bd7b65..52573498 100644 --- a/Demo/Demo/ExploreViewController.swift +++ b/Demo/Demo/ExploreViewController.swift @@ -27,7 +27,7 @@ class ExploreViewController: UITableViewController, UITextFieldDelegate { view = try! SwiftMessages.viewFromNib() } - view.configureContent(title: titleText.text, body: bodyText.text, iconImage: nil, iconText: nil, buttonImage: nil, buttonTitle: "Hide", buttonTapHandler: { _ in SwiftMessages.hide() }) + view.configureContent(title: titleText.text, body: bodyText.text, iconImage: nil, iconText: nil, buttonImage: nil, buttonTitle: "Hide", buttonTapHandler: { _ in SwiftMessages.hide(animated: false) }) let iconStyle: IconStyle switch self.iconStyle.selectedSegmentIndex { diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index 6695502f..4aab80f1 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -175,11 +175,11 @@ class Presenter: NSObject { var isHiding = false - func hide(completion: @escaping AnimationCompletion) { + func hide(animated: Bool, completion: @escaping AnimationCompletion) { isHiding = true self.config.eventListeners.forEach { $0(.willHide) } let context = animationContext() - animator.hide(context: context) { (completed) in + let action = { if let viewController = self.presentationContext.viewControllerValue() as? WindowViewController { viewController.uninstall() } @@ -187,6 +187,13 @@ class Presenter: NSObject { completion(true) self.config.eventListeners.forEach { $0(.didHide) } } + guard animated else { + action() + return + } + animator.hide(context: context) { (completed) in + action() + } func undim() { UIView.animate(withDuration: 0.2, delay: 0, options: .beginFromCurrentState, animations: { diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index 35650228..fd46ade7 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -385,9 +385,9 @@ open class SwiftMessages { /** Hide the current message being displayed by animating it away. */ - open func hide() { + open func hide(animated: Bool = true) { messageQueue.sync { - hideCurrent() + hideCurrent(animated: animated) } } @@ -572,11 +572,10 @@ open class SwiftMessages { delays.ids.remove(id) } - fileprivate func hideCurrent() { + fileprivate func hideCurrent(animated: Bool = true) { guard let current = _current, !current.isHiding else { return } - let delay = current.delayHide ?? 0 - DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in - current.hide { (completed) in + let action = { [weak self] in + current.hide(animated: animated) { (completed) in guard completed, let strongSelf = self else { return } strongSelf.messageQueue.sync { guard strongSelf._current === current else { return } @@ -585,6 +584,10 @@ open class SwiftMessages { } } } + let delay = current.delayHide ?? 0 + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + action() + } } fileprivate weak var autohideToken: AnyObject? @@ -829,8 +832,8 @@ extension SwiftMessages { globalInstance.show(config: config, view: view) } - public static func hide() { - globalInstance.hide() + public static func hide(animated: Bool = true) { + globalInstance.hide(animated: animated) } public static func hideAll() { From f47eaabb4f393b8754b75160305d2f3f2083d65b Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Wed, 23 Jan 2019 08:52:07 -0600 Subject: [PATCH 009/139] Make pan gesture recognizers public --- CHANGELOG.md | 1 + SwiftMessages/PhysicsPanHandler.swift | 2 +- SwiftMessages/TopBottomAnimation.swift | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 770d7f66..bf028013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. * #276 Add ability to hide message without animation * #272 Add duration for `SwiftMessagesSegue` +* #278 Make pan gesture recognizers public ## 6.0.2 diff --git a/SwiftMessages/PhysicsPanHandler.swift b/SwiftMessages/PhysicsPanHandler.swift index 1c4f1816..da82fc18 100644 --- a/SwiftMessages/PhysicsPanHandler.swift +++ b/SwiftMessages/PhysicsPanHandler.swift @@ -91,7 +91,7 @@ open class PhysicsPanHandler { public init() {} - lazy var pan: UIPanGestureRecognizer = { + public private(set) lazy var pan: UIPanGestureRecognizer = { let pan = UIPanGestureRecognizer() pan.addTarget(self, action: #selector(pan(_:))) return pan diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index 59196ea1..61aaf10d 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -27,6 +27,8 @@ public class TopBottomAnimation: NSObject, Animator { open var closeAbsoluteThreshold: CGFloat = 75.0; + public private(set) var panGestureRecognizer: UIPanGestureRecognizer? + weak var messageView: UIView? weak var containerView: UIView? var context: AnimationContext? @@ -103,6 +105,7 @@ public class TopBottomAnimation: NSObject, Animator { } if context.interactiveHide { let pan = UIPanGestureRecognizer() + self.panGestureRecognizer = pan pan.addTarget(self, action: #selector(pan(_:))) if let view = view as? BackgroundViewable { view.backgroundView.addGestureRecognizer(pan) From 30fbed8a4e3283c5814169c4ebc78a28a6656da6 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Wed, 23 Jan 2019 17:13:34 -0600 Subject: [PATCH 010/139] Lazily instantiate pan gesture recognizer --- SwiftMessages/TopBottomAnimation.swift | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index 61aaf10d..fb4d623f 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -27,7 +27,11 @@ public class TopBottomAnimation: NSObject, Animator { open var closeAbsoluteThreshold: CGFloat = 75.0; - public private(set) var panGestureRecognizer: UIPanGestureRecognizer? + public private(set) lazy var panGestureRecognizer: UIPanGestureRecognizer = { + let pan = UIPanGestureRecognizer() + pan.addTarget(self, action: #selector(pan(_:))) + return pan + }() weak var messageView: UIView? weak var containerView: UIView? @@ -104,13 +108,10 @@ public class TopBottomAnimation: NSObject, Animator { view.transform = CGAffineTransform(translationX: 0, y: animationDistance) } if context.interactiveHide { - let pan = UIPanGestureRecognizer() - self.panGestureRecognizer = pan - pan.addTarget(self, action: #selector(pan(_:))) if let view = view as? BackgroundViewable { - view.backgroundView.addGestureRecognizer(pan) + view.backgroundView.addGestureRecognizer(panGestureRecognizer) } else { - view.addGestureRecognizer(pan) + view.addGestureRecognizer(panGestureRecognizer) } } if let view = view as? BackgroundViewable, From b2af6d4c4fbc5a09d90d9893658e23fbc5214856 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 30 Mar 2019 14:47:00 -0500 Subject: [PATCH 011/139] Swift 5 updates --- Demo/Demo.xcodeproj/project.pbxproj | 10 ++++++---- .../xcshareddata/xcschemes/Demo.xcscheme | 2 +- Demo/Demo/ExploreViewController.swift | 2 +- Demo/Demo/ViewController.swift | 2 +- SwiftMessages.xcodeproj/project.pbxproj | 16 +++++++++------- .../xcschemes/SwiftMessages.xcscheme | 2 +- SwiftMessages/Array+Utils.swift | 4 ++-- SwiftMessages/BaseView.swift | 4 ++-- SwiftMessages/MarginAdjustable+Animation.swift | 3 +-- SwiftMessages/MarginAdjustable.swift | 6 +++--- SwiftMessages/MaskingView.swift | 2 +- SwiftMessages/MessageView.swift | 1 + SwiftMessages/Resources/CardView.xib | 11 +++++------ SwiftMessages/Resources/CenteredView.xib | 15 +++++++-------- SwiftMessages/Resources/MessageView.xib | 11 +++++------ SwiftMessages/Resources/StatusLine.xib | 7 +++---- SwiftMessages/Resources/TabView.xib | 11 +++++------ 17 files changed, 54 insertions(+), 55 deletions(-) diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index 780b3fd6..d04f4ebd 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -195,7 +195,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0940; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = "SwiftKick Mobile"; TargetAttributes = { 86AEDCE11D5D1DB70030232E = { @@ -207,7 +207,7 @@ }; buildConfigurationList = 86AEDCDD1D5D1DB70030232E /* Build configuration list for PBXProject "Demo" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -315,6 +315,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -371,6 +372,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -428,7 +430,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.Demo; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -443,7 +445,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.Demo; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme b/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme index 512dc8b6..97e4882f 100644 --- a/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme +++ b/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme @@ -1,6 +1,6 @@ Iterator.Element? { guard count > 0 else { return nil } return self[Int(arc4random_uniform(UInt32(count)))] diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index ec9de4ce..a963e4b7 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -234,7 +234,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable { view.removeConstraint(existing) backgroundHeightConstraint = nil } - if let height = backgroundHeight { + if let height = backgroundHeight, let backgroundView = backgroundView { let constraint = NSLayoutConstraint(item: backgroundView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: height) backgroundView.addConstraint(constraint) backgroundHeightConstraint = constraint @@ -256,7 +256,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable { Note that this height is not guaranteed depending on anyt Auto Layout constraints used within the message view. */ - @available(*, deprecated:4.2.0, message:"Use `backgroundHeight` instead to specify preferred height of the visible region of the message.") + @available(*, message:"Use `backgroundHeight` instead to specify preferred height of the visible region of the message.") open var preferredHeight: CGFloat? { didSet { setNeedsLayout() diff --git a/SwiftMessages/MarginAdjustable+Animation.swift b/SwiftMessages/MarginAdjustable+Animation.swift index 5cba17e7..579351df 100644 --- a/SwiftMessages/MarginAdjustable+Animation.swift +++ b/SwiftMessages/MarginAdjustable+Animation.swift @@ -8,8 +8,7 @@ import UIKit -public extension MarginAdjustable where Self: UIView { - +extension MarginAdjustable where Self: UIView { public func defaultMarginAdjustment(context: AnimationContext) -> UIEdgeInsets { // Best effort to determine if we should use the new or deprecated margin adjustments. if layoutMarginAdditions != .zero diff --git a/SwiftMessages/MarginAdjustable.swift b/SwiftMessages/MarginAdjustable.swift index ed44dc11..44b0c11c 100644 --- a/SwiftMessages/MarginAdjustable.swift +++ b/SwiftMessages/MarginAdjustable.swift @@ -40,13 +40,13 @@ public protocol MarginAdjustable { */ /// Top margin adjustment for status bar avoidance in pre-iOS 11+ - @available(iOS, deprecated, message: "Now handled by `collapseLayoutMarginAdditions`") + @available(*, deprecated, message: "Now handled by `collapseLayoutMarginAdditions`") var statusBarOffset: CGFloat { get set } /// Safe area top adjustment in iOS 11+ - @available(iOS, deprecated, message: "Use the `topLayoutMarginAddition` instead.") + @available(*, deprecated, message: "Use the `topLayoutMarginAddition` instead.") var safeAreaTopOffset: CGFloat { get set } /// Safe area bottom adjustment in iOS 11+ - @available(iOS, deprecated, message: "Use the `bottomLayoutMarginAddition` instead.") + @available(*, deprecated, message: "Use the `bottomLayoutMarginAddition` instead.") var safeAreaBottomOffset: CGFloat { get set } } diff --git a/SwiftMessages/MaskingView.swift b/SwiftMessages/MaskingView.swift index ed6c068c..e0bb929c 100644 --- a/SwiftMessages/MaskingView.swift +++ b/SwiftMessages/MaskingView.swift @@ -36,7 +36,7 @@ class MaskingView: PassthroughView { override func index(ofAccessibilityElement element: Any) -> Int { guard let object = element as? NSObject else { return 0 } - return accessibleElements.index(of: object) ?? 0 + return accessibleElements.firstIndex(of: object) ?? 0 } init() { diff --git a/SwiftMessages/MessageView.swift b/SwiftMessages/MessageView.swift index f3cfe0bf..30169137 100644 --- a/SwiftMessages/MessageView.swift +++ b/SwiftMessages/MessageView.swift @@ -416,6 +416,7 @@ extension MessageView { this method. */ public func configureBackgroundView(width: CGFloat) { + guard let backgroundView = backgroundView else { return } let constraint = NSLayoutConstraint(item: backgroundView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: width) backgroundView.addConstraint(constraint) } diff --git a/SwiftMessages/Resources/CardView.xib b/SwiftMessages/Resources/CardView.xib index b64b4203..38c194fb 100644 --- a/SwiftMessages/Resources/CardView.xib +++ b/SwiftMessages/Resources/CardView.xib @@ -1,12 +1,11 @@ - + - - - + + @@ -32,10 +31,10 @@ - + - + - + diff --git a/SwiftMessages/Resources/MessageView.xib b/SwiftMessages/Resources/MessageView.xib index 498d8b44..c078b08c 100644 --- a/SwiftMessages/Resources/MessageView.xib +++ b/SwiftMessages/Resources/MessageView.xib @@ -1,12 +1,11 @@ - + - - - + + @@ -29,10 +28,10 @@ - + - + - + - + diff --git a/SwiftMessages/Resources/CenteredView.xib b/SwiftMessages/Resources/CenteredView.xib index 58397391..93f6fdff 100644 --- a/SwiftMessages/Resources/CenteredView.xib +++ b/SwiftMessages/Resources/CenteredView.xib @@ -1,6 +1,6 @@ - + @@ -12,17 +12,17 @@ - + - + - - + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -79,9 +98,13 @@ + + + + @@ -101,6 +124,20 @@ + + + + + + + + + + + + + + @@ -109,7 +146,7 @@ - + diff --git a/SwiftMessages/Resources/MessageView.xib b/SwiftMessages/Resources/MessageView.xib index c078b08c..755cc583 100644 --- a/SwiftMessages/Resources/MessageView.xib +++ b/SwiftMessages/Resources/MessageView.xib @@ -1,6 +1,6 @@ - + @@ -16,10 +16,10 @@ - + - + - + + diff --git a/SwiftMessages/Resources/StatusLine.xib b/SwiftMessages/Resources/StatusLine.xib index ed76f458..52ae0e3f 100644 --- a/SwiftMessages/Resources/StatusLine.xib +++ b/SwiftMessages/Resources/StatusLine.xib @@ -1,23 +1,22 @@ - + - - + diff --git a/SwiftMessages/Resources/TabView.xib b/SwiftMessages/Resources/TabView.xib index dba48027..bd059909 100644 --- a/SwiftMessages/Resources/TabView.xib +++ b/SwiftMessages/Resources/TabView.xib @@ -1,6 +1,6 @@ - + @@ -19,10 +19,10 @@ - + - + - + + + @@ -78,15 +80,27 @@ + + + + + + + + + + + + @@ -109,6 +123,20 @@ + + + + + + + + + + + + + + From 753b0a845cce5fc503f3cd99064d3c93ed0c79f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20C=C5=93ur?= Date: Sun, 31 Mar 2019 05:06:26 +0800 Subject: [PATCH 013/139] Fix .indefinite potential incorrect duration calculation by using a monotonic clock (#295) --- SwiftMessages/Presenter.swift | 4 ++-- SwiftMessages/SwiftMessages.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index 4aab80f1..dc3d19f1 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -87,7 +87,7 @@ class Presenter: NSObject { return duration } - var showDate: Date? + var showDate: CFTimeInterval? private var interactivelyHidden = false; @@ -100,7 +100,7 @@ class Presenter: NSObject { var delayHide: TimeInterval? { if interactivelyHidden { return 0 } if case .indefinite(let opts) = config.duration, let showDate = showDate { - let timeIntervalShown = -showDate.timeIntervalSinceNow + let timeIntervalShown = CACurrentMediaTime() - showDate return max(0, opts.minimum - timeIntervalShown) } return nil diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index fd46ade7..8b1d865f 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -540,7 +540,7 @@ open class SwiftMessages { // the dismiss gesture begins before we've queued the autohide // block on animation completion. self.autohideToken = current - current.showDate = Date() + current.showDate = CACurrentMediaTime() DispatchQueue.main.async { [weak self] in guard let strongSelf = self else { return } do { From e2f050edc7d94b4ae3e257081af4efcd04f462da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20C=C5=93ur?= Date: Sun, 31 Mar 2019 05:12:49 +0800 Subject: [PATCH 014/139] Fix: Unexpected version number in 'available' attribute for non-specific platform '*' (#283) --- SwiftMessages/BaseView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index ec9de4ce..fa431440 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -256,7 +256,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable { Note that this height is not guaranteed depending on anyt Auto Layout constraints used within the message view. */ - @available(*, deprecated:4.2.0, message:"Use `backgroundHeight` instead to specify preferred height of the visible region of the message.") + @available(*, deprecated, message:"Use `backgroundHeight` instead to specify preferred height of the visible region of the message.") open var preferredHeight: CGFloat? { didSet { setNeedsLayout() From 3b46f94ca7ea04f55d36f9f6daebf99f2ce56e46 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 8 Apr 2019 10:14:29 -0500 Subject: [PATCH 015/139] Add iPad icons --- .../AppIcon.appiconset/Contents.json | 54 ++++++++++++++++++ .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 815 bytes .../Icon-App-20x20@2x-1.png | Bin 0 -> 2349 bytes .../Icon-App-20x20@2x-2.png | Bin 0 -> 2349 bytes .../Icon-App-29x29@1x-1.png | Bin 0 -> 1408 bytes .../Icon-App-29x29@2x-1.png | Bin 0 -> 4184 bytes .../Icon-App-40x40@2x-1.png | Bin 0 -> 7041 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 6469 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 21607 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 25584 bytes SwiftMessages.podspec | 4 +- SwiftMessages.xcodeproj/project.pbxproj | 4 +- 12 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-2.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x-1.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json index d74e5aa2..2eeb86b6 100644 --- a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -54,6 +54,60 @@ "filename" : "Icon-App-60x60@3x.png", "scale" : "3x" }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x-1.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x-2.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, { "size" : "1024x1024", "idiom" : "ios-marketing", diff --git a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..f3637f34585aa7f51b70ec87c8eea522c6d8e90a GIT binary patch literal 815 zcmV+~1JL}5P)Px%=}AOER5%fJR6S2rQ4l@v?E)+EB?>VZ6Nza2prSOf(89`6EllhzG!_=d7;TM) z#y?8A$E2o7KVz1U@*Z539@8a*oA%XdCtte50rSbd*9rdGc#xAek9|cR|;@w zN+f6`LDHu*1cADuC1FlE5#%0WMQ^K$EG^JK?x~CgSr(ZrE*opbv_B`c zC9Z>fbF_v_N2}D+KwrfWCY3W;n?Xv+#z08|NZ*rPDXtE8<5YLW^fSM9FjlMJ&e#z; z%ZHBqvt-5M6dLVqOG=%9PcIDO;n{wq#N@=jUE0F*!X_3Qd)U~^abu(hv#V|MVab6> z`E|BdCUq|-kKxh8fCUp11%1Ha*GFo|Sn92@UMy^ON`@?%c{1#RWo&>hBgz=t+(y=_@?B!Erz(02gh0~!_3My zE)I5KysrzjN`j@WJ-nW;vv0eECit@2;+Lm`6%~xbtLJ33(=WcRV{L)Z3ZtxXn$`6|~d9QvIBU zZA6U+I_hb$} t>YHRbdUgrc7-y&F$j^-7{Bbc6e*k4T%JBQ`8`b~-002ovPDHLkV1fx2g1`U( literal 0 HcmV?d00001 diff --git a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..7cad51b4f6eb5d89012220f9e4b4ba89852a098b GIT binary patch literal 2349 zcmV+|3DWk7P)Px-=Sf6CR9FeMmrIP6XBEfKH+;ZcxKj$)4wq`QmtbwJrimD&8V*(50p(YFZQ9#2OW8n`+yIQV6AhFu)XMU|^Wf|L=dE^M2nnt-VB_ zZ{GJg@45WX|2fa)eW$nksn-V)1N|a;y4-q5rO6(T9v=D|3?$p9`P;kMQFTB=`}>vp z%4RACXuuFa+3S_95yIDcvus1?sfV0e5nIYQ2GI=$8)N0h;4F{CV0w$zF937mre@&g zY+R{366g!uBIKn)HxdtR{;0Zh4CG`m0J6Cd5%NFK&-9Zu!;`Rm6JKHr6x9T<3ZhMn*?8`&dr{RWt8Pg!UAg*%M8w8uZ$2*WopTcIU)dW?*4Gc!b6Wij0Q$W6-SidU1f7ix%?A1#s(vANg1gZ7fQ+2W>=)> zSB*tHdi#d>^3Ev_Kq@yXcj&}ieCMT$AzqID{Pv0XrhE@yScvbvG8?BBmRw;EybTsl zzv>!FgR4#{1*VBBMfSyy^6OXDl_K|(dvA&dZXRFmuP2f|vSUrm-x$PqU!FC?>4|>q zKQa@~tFnbrfnGkXAiW*GIz9lPYw|XS%G?+?#|vwZO5Ou5=ykZt=?4?L2}aw4CDL zy_?>VoN+afFHKJ&dVd`F;MzF6Z+m>>!|USc++uwFx%0MhBe$;|zdWuqJTP6FHi39& zqHL{n?xl0V+W>y}@y+qjEtBQ?j{OB~h)+IwN^5Ztcdc6)GuM{l^wk>)%Cf2aEy)*tIff+R@ci;wyr+_ULDkppYvsul4u?Q*dG@y4RaEjibA?XcZbYzY~p zaW3`Un}lFW<2u%qQey~-&9sh;uYPE4+^YVCi`Qa)aVZ{d)8*LraNDaj_t%*P0T1Hw z`?tjXdcLSi{!Kf2|KXWT%3Zm07gJ7%n7ss-H>*Y7T^iXF4{VFIY*n?-X+dAU&Z+(W z+8!#XM!o}w&&7fYqEiM6Xg$q-5Ut_If{olDo33~0)PHo(hPZF@c#P|S9c^nG*-_oQ zmHR+Z2mKaw^la0Sb9Ui|W+jW`Hx@+o%MVu8l=HVp#c$VC{^HX&$9k=q|8+a7P2p2R z>Gp1!h;Q%N80$6Qhn_wi$F-X~F5=sVt!LOHY9mkuzc@Yle<8}IAh;r_+OJC3t!p2W>axgJJDWLUc+5nPN^rnCQ zYE3xs-2$yr-=c4$J2$S1W0w}=f~s)j3p?yrx8J@t7hik!oJc{7_)L~l)ZR`?oK`j? zZ>q|ZgDHCWbj7k$RZxZmP;UW*RGyr_5hv%fI#XJgiyC=-tL7 zMC2=w*t~|Az@f~(K1$H}HH#knH}wvYT3<7|W3S$>+**}duzjTc&57k-zO#A-{6R;B z0V_&)ExP+kVgU7j4szjDU=0F2)pxw)v0_>Qj3)p0pa+R2cRBL>JAIlj6&qRZ-n=@t zjq5OPu8y&gHcZ_J-ntLKbmUpFj31LsJ_KypGO3CrH<(- z9n9l-`Y)C3X@}y0t;rUynr| zo8^{=BDC+p;bH|v=?uhDq%!o@LCb)o6=|OBWQiaQYMpoL@Uc!^xl}KctB(s~@S#Xp zI_Qg90>)8Lo~15~l2gs_HBKefYV5!*1BH_=@X=Lsb!5yQADr;Zg4o+K0K@hlLezdA T@X}1%00000NkvXXu0mjfjkc0E literal 0 HcmV?d00001 diff --git a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-2.png b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-2.png new file mode 100644 index 0000000000000000000000000000000000000000..7cad51b4f6eb5d89012220f9e4b4ba89852a098b GIT binary patch literal 2349 zcmV+|3DWk7P)Px-=Sf6CR9FeMmrIP6XBEfKH+;ZcxKj$)4wq`QmtbwJrimD&8V*(50p(YFZQ9#2OW8n`+yIQV6AhFu)XMU|^Wf|L=dE^M2nnt-VB_ zZ{GJg@45WX|2fa)eW$nksn-V)1N|a;y4-q5rO6(T9v=D|3?$p9`P;kMQFTB=`}>vp z%4RACXuuFa+3S_95yIDcvus1?sfV0e5nIYQ2GI=$8)N0h;4F{CV0w$zF937mre@&g zY+R{366g!uBIKn)HxdtR{;0Zh4CG`m0J6Cd5%NFK&-9Zu!;`Rm6JKHr6x9T<3ZhMn*?8`&dr{RWt8Pg!UAg*%M8w8uZ$2*WopTcIU)dW?*4Gc!b6Wij0Q$W6-SidU1f7ix%?A1#s(vANg1gZ7fQ+2W>=)> zSB*tHdi#d>^3Ev_Kq@yXcj&}ieCMT$AzqID{Pv0XrhE@yScvbvG8?BBmRw;EybTsl zzv>!FgR4#{1*VBBMfSyy^6OXDl_K|(dvA&dZXRFmuP2f|vSUrm-x$PqU!FC?>4|>q zKQa@~tFnbrfnGkXAiW*GIz9lPYw|XS%G?+?#|vwZO5Ou5=ykZt=?4?L2}aw4CDL zy_?>VoN+afFHKJ&dVd`F;MzF6Z+m>>!|USc++uwFx%0MhBe$;|zdWuqJTP6FHi39& zqHL{n?xl0V+W>y}@y+qjEtBQ?j{OB~h)+IwN^5Ztcdc6)GuM{l^wk>)%Cf2aEy)*tIff+R@ci;wyr+_ULDkppYvsul4u?Q*dG@y4RaEjibA?XcZbYzY~p zaW3`Un}lFW<2u%qQey~-&9sh;uYPE4+^YVCi`Qa)aVZ{d)8*LraNDaj_t%*P0T1Hw z`?tjXdcLSi{!Kf2|KXWT%3Zm07gJ7%n7ss-H>*Y7T^iXF4{VFIY*n?-X+dAU&Z+(W z+8!#XM!o}w&&7fYqEiM6Xg$q-5Ut_If{olDo33~0)PHo(hPZF@c#P|S9c^nG*-_oQ zmHR+Z2mKaw^la0Sb9Ui|W+jW`Hx@+o%MVu8l=HVp#c$VC{^HX&$9k=q|8+a7P2p2R z>Gp1!h;Q%N80$6Qhn_wi$F-X~F5=sVt!LOHY9mkuzc@Yle<8}IAh;r_+OJC3t!p2W>axgJJDWLUc+5nPN^rnCQ zYE3xs-2$yr-=c4$J2$S1W0w}=f~s)j3p?yrx8J@t7hik!oJc{7_)L~l)ZR`?oK`j? zZ>q|ZgDHCWbj7k$RZxZmP;UW*RGyr_5hv%fI#XJgiyC=-tL7 zMC2=w*t~|Az@f~(K1$H}HH#knH}wvYT3<7|W3S$>+**}duzjTc&57k-zO#A-{6R;B z0V_&)ExP+kVgU7j4szjDU=0F2)pxw)v0_>Qj3)p0pa+R2cRBL>JAIlj6&qRZ-n=@t zjq5OPu8y&gHcZ_J-ntLKbmUpFj31LsJ_KypGO3CrH<(- z9n9l-`Y)C3X@}y0t;rUynr| zo8^{=BDC+p;bH|v=?uhDq%!o@LCb)o6=|OBWQiaQYMpoL@Uc!^xl}KctB(s~@S#Xp zI_Qg90>)8Lo~15~l2gs_HBKefYV5!*1BH_=@X=Lsb!5yQADr;Zg4o+K0K@hlLezdA T@X}1%00000NkvXXu0mjfjkc0E literal 0 HcmV?d00001 diff --git a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x-1.png b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..0849f15345d635ba05327ea0c24e29bb0c7a6b62 GIT binary patch literal 1408 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 literal 0 HcmV?d00001 diff --git a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..1560730ff70101e8fc4966e43d750ac505e7603f GIT binary patch literal 6469 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 li2EF@M5002ovPDHLkV1ffEkoy1t literal 0 HcmV?d00001 diff --git a/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Demo/Demo/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4482fe4368da5b55172149a8725a463295cc3f6a GIT binary patch literal 25584 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�+!yF+Q@^FRu}U!KU9#Fw51O2*g) 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 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } spec.summary = 'A very flexible message bar for iOS written in Swift.' spec.source = {:git => 'https://github.com/SwiftKickMobile/SwiftMessages.git', :tag => spec.version} spec.platform = :ios, '9.0' - spec.swift_version = '4.2' + spec.swift_version = '5' spec.ios.deployment_target = '9.0' spec.framework = 'UIKit' spec.requires_arc = true diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 9c789500..913f48bc 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -723,7 +723,7 @@ PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessagesTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -735,7 +735,7 @@ PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessagesTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Release; }; From 7371b0736cb4823079fb5a314efe4897d3b08748 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 8 Apr 2019 10:27:37 -0500 Subject: [PATCH 016/139] Animate hiding --- Demo/Demo.xcodeproj/project.pbxproj | 4 ++-- Demo/Demo/ExploreViewController.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index b52905ef..e793e1ad 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -430,7 +430,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.Demo; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -446,7 +446,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.Demo; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Demo/Demo/ExploreViewController.swift b/Demo/Demo/ExploreViewController.swift index a55c1aa6..d39009a2 100644 --- a/Demo/Demo/ExploreViewController.swift +++ b/Demo/Demo/ExploreViewController.swift @@ -27,7 +27,7 @@ class ExploreViewController: UITableViewController, UITextFieldDelegate { view = try! SwiftMessages.viewFromNib() } - view.configureContent(title: titleText.text, body: bodyText.text, iconImage: nil, iconText: nil, buttonImage: nil, buttonTitle: "Hide", buttonTapHandler: { _ in SwiftMessages.hide(animated: false) }) + view.configureContent(title: titleText.text, body: bodyText.text, iconImage: nil, iconText: nil, buttonImage: nil, buttonTitle: "Hide", buttonTapHandler: { _ in SwiftMessages.hide() }) let iconStyle: IconStyle switch self.iconStyle.selectedSegmentIndex { From 2dd48d76b21c0b8d87e49a6bbc20e857add92d70 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 29 Apr 2019 10:49:57 -0500 Subject: [PATCH 017/139] Fix swift version string --- SwiftMessages.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 7ea9b74c..3ae875a2 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -7,7 +7,7 @@ Pod::Spec.new do |spec| spec.summary = 'A very flexible message bar for iOS written in Swift.' spec.source = {:git => 'https://github.com/SwiftKickMobile/SwiftMessages.git', :tag => spec.version} spec.platform = :ios, '9.0' - spec.swift_version = '5' + spec.swift_version = '5.0' spec.ios.deployment_target = '9.0' spec.framework = 'UIKit' spec.requires_arc = true From da4d16c3ec9fa84259a1cceed35f2b6d46d7521b Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 18 May 2019 12:27:16 -0500 Subject: [PATCH 018/139] Remove deprecated APIs --- SwiftMessages.xcodeproj/project.pbxproj | 4 - SwiftMessages/Array+Utils.swift | 21 ---- SwiftMessages/BaseView.swift | 35 ------- .../MarginAdjustable+Animation.swift | 97 ++++--------------- SwiftMessages/MarginAdjustable.swift | 14 --- SwiftMessages/SwiftMessagesSegue.swift | 3 - 6 files changed, 18 insertions(+), 156 deletions(-) delete mode 100644 SwiftMessages/Array+Utils.swift diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 913f48bc..efeb1fec 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -76,7 +76,6 @@ 86BBA9061D5E040C00FE8F16 /* Identifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 864495551D4F7C390056EB2A /* Identifiable.swift */; }; 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86AAF81D1D5549680031EE32 /* MarginAdjustable.swift */; }; 86BBA9081D5E040C00FE8F16 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86AAF82A1D580DD70031EE32 /* Error.swift */; }; - 86DBE0041D75BE800071E51D /* Array+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86DBE0031D75BE800071E51D /* Array+Utils.swift */; }; E6E49F911D70A344006CB883 /* MessageView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 862C0CDA1D5A397F00D06168 /* MessageView.xib */; }; E6E49F921D70A349006CB883 /* StatusLine.xib in Resources */ = {isa = PBXBuildFile; fileRef = 862C0CDB1D5A397F00D06168 /* StatusLine.xib */; }; /* End PBXBuildFile section */ @@ -167,7 +166,6 @@ 86B48AFA1D5A41C900063E2B /* SwiftMessagesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMessagesTests.swift; sourceTree = ""; }; 86B48AFC1D5A41C900063E2B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86BBA8F81D5E01FC00FE8F16 /* CardView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CardView.xib; path = Resources/CardView.xib; sourceTree = ""; }; - 86DBE0031D75BE800071E51D /* Array+Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Utils.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -277,7 +275,6 @@ 86AAF82A1D580DD70031EE32 /* Error.swift */, 2298C2061EE480D000E2DDC1 /* Animator.swift */, 2298C2041EE47DC900E2DDC1 /* Weak.swift */, - 86DBE0031D75BE800071E51D /* Array+Utils.swift */, 22774B9F20B5EF2A00813732 /* UIEdgeInsets+Utils.swift */, 22F27950210CE25900273E7F /* CornerRoundingView.swift */, ); @@ -531,7 +528,6 @@ 86589D471D64B6E40041676C /* BaseView.swift in Sources */, 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */, 867BED211D622793005212E3 /* BackgroundViewable.swift in Sources */, - 86DBE0041D75BE800071E51D /* Array+Utils.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SwiftMessages/Array+Utils.swift b/SwiftMessages/Array+Utils.swift deleted file mode 100644 index 391bcc17..00000000 --- a/SwiftMessages/Array+Utils.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Array+Utils.swift -// SwiftMessages -// -// Created by Tim Moose on 8/30/16. -// Copyright Β© 2016 SwiftKick Mobile. All rights reserved. -// - -import Darwin - -extension Array { - /** - Returns a random element from the array. Can be used to create a playful - message that cycles randomly through a set of emoji icons, for example. - */ - @available(*, deprecated, message: "Use randomElement() instead.") - public func sm_random() -> Iterator.Element? { - guard count > 0 else { return nil } - return self[Int(arc4random_uniform(UInt32(count)))] - } -} diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index e9355656..e30f7924 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -204,15 +204,6 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable { @IBInspectable open var collapseLayoutMarginAdditions: Bool = true @IBInspectable open var bounceAnimationOffset: CGFloat = 5 - - /// Deprecated - @objc open var statusBarOffset: CGFloat = 0 - - /// Deprecated - @objc open var safeAreaTopOffset: CGFloat = 0 - - /// Deprecated - @objc open var safeAreaBottomOffset: CGFloat = 0 /* MARK: - Setting the height @@ -242,33 +233,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable { } private var backgroundHeightConstraint: NSLayoutConstraint? - - open override var intrinsicContentSize: CGSize { - if let preferredHeight = (self as InternalPreferredHeight).preferredHeight { - return CGSize(width: UIView.noIntrinsicMetric, height: preferredHeight) - } - return super.intrinsicContentSize - } - - /** - An optional value that sets the message view's intrinsic content height. - This can be used as a way to specify a fixed height for the message view. - Note that this height is not guaranteed depending on anyt Auto Layout - constraints used within the message view. - */ - @available(*, deprecated, message:"Use `backgroundHeight` instead to specify preferred height of the visible region of the message.") - open var preferredHeight: CGFloat? { - didSet { - setNeedsLayout() - } - } -} - -// A workaround to prevent warning on deprecated property. -private protocol InternalPreferredHeight { - var preferredHeight: CGFloat? { get } } -extension BaseView: InternalPreferredHeight {} /* MARK: - Theming diff --git a/SwiftMessages/MarginAdjustable+Animation.swift b/SwiftMessages/MarginAdjustable+Animation.swift index 579351df..3829a70c 100644 --- a/SwiftMessages/MarginAdjustable+Animation.swift +++ b/SwiftMessages/MarginAdjustable+Animation.swift @@ -10,95 +10,34 @@ import UIKit extension MarginAdjustable where Self: UIView { public func defaultMarginAdjustment(context: AnimationContext) -> UIEdgeInsets { - // Best effort to determine if we should use the new or deprecated margin adjustments. - if layoutMarginAdditions != .zero - || (safeAreaTopOffset == 0 && safeAreaBottomOffset == 0 && statusBarOffset == 0) { - var layoutMargins: UIEdgeInsets = layoutMarginAdditions - var safeAreaInsets: UIEdgeInsets - if #available(iOS 11, *) { - insetsLayoutMarginsFromSafeArea = false - safeAreaInsets = self.safeAreaInsets - } else { - #if SWIFTMESSAGES_APP_EXTENSIONS - let application: UIApplication? = nil - #else - let application: UIApplication? = UIApplication.shared - #endif - if !context.safeZoneConflicts.isDisjoint(with: [.statusBar]), - let app = application, - app.statusBarOrientation == .portrait || app.statusBarOrientation == .portraitUpsideDown { - let frameInWindow = convert(bounds, to: window) - let top = max(0, 20 - frameInWindow.minY) - safeAreaInsets = UIEdgeInsets(top: top, left: 0, bottom: 0, right: 0) - } else { - safeAreaInsets = .zero - } - } - if !context.safeZoneConflicts.isDisjoint(with: .overStatusBar) { - safeAreaInsets.top = 0 - } - layoutMargins = collapseLayoutMarginAdditions - ? layoutMargins.collapse(toInsets: safeAreaInsets) - : layoutMargins + safeAreaInsets - return layoutMargins + var layoutMargins: UIEdgeInsets = layoutMarginAdditions + var safeAreaInsets: UIEdgeInsets + if #available(iOS 11, *) { + insetsLayoutMarginsFromSafeArea = false + safeAreaInsets = self.safeAreaInsets } else { - var insets: UIEdgeInsets - if #available(iOS 11, *) { - insets = safeAreaInsets - } else { - insets = .zero - } - insets.top += topAdjustment(context: context) - insets.bottom += bottomAdjustment(context: context) - return insets - } - } - - private func topAdjustment(context: AnimationContext) -> CGFloat { - var top: CGFloat = 0 - if !context.safeZoneConflicts.isDisjoint(with: [.sensorNotch, .statusBar]) { #if SWIFTMESSAGES_APP_EXTENSIONS let application: UIApplication? = nil #else let application: UIApplication? = UIApplication.shared #endif - if #available(iOS 11, *), safeAreaInsets.top > 0 { - do { - // To accommodate future safe areas, using a linear formula based on - // two data points: - // iPhone 8 - 20pt top safe area needs 0pt adjustment - // iPhone X - 44pt top safe area needs -6pt adjustment - top -= 6 * (safeAreaInsets.top - 20) / (44 - 20) - } - top += safeAreaTopOffset - } else if let app = application, app.statusBarOrientation == .portrait || app.statusBarOrientation == .portraitUpsideDown { + if !context.safeZoneConflicts.isDisjoint(with: [.statusBar]), + let app = application, + app.statusBarOrientation == .portrait || app.statusBarOrientation == .portraitUpsideDown { let frameInWindow = convert(bounds, to: window) - if frameInWindow.minY == -bounceAnimationOffset { - top += statusBarOffset - } + let top = max(0, 20 - frameInWindow.minY) + safeAreaInsets = UIEdgeInsets(top: top, left: 0, bottom: 0, right: 0) + } else { + safeAreaInsets = .zero } - } else if #available(iOS 11, *), !context.safeZoneConflicts.isDisjoint(with: .overStatusBar) { - top -= safeAreaInsets.top } - return top - } - - private func bottomAdjustment(context: AnimationContext) -> CGFloat { - var bottom: CGFloat = 0 - if !context.safeZoneConflicts.isDisjoint(with: [.homeIndicator]) { - if #available(iOS 11, *), safeAreaInsets.bottom > 0 { - do { - // This adjustment was added to fix a layout issue with iPhone X in - // landscape mode. Using a linear formula based on two data points to help - // future proof against future safe areas: - // iPhone X portrait: 34pt bottom safe area needs 0pt adjustment - // iPhone X landscape: 21pt bottom safe area needs 12pt adjustment - bottom -= 12 * (safeAreaInsets.bottom - 34) / (34 - 21) - } - bottom += safeAreaBottomOffset - } + if !context.safeZoneConflicts.isDisjoint(with: .overStatusBar) { + safeAreaInsets.top = 0 } - return bottom + layoutMargins = collapseLayoutMarginAdditions + ? layoutMargins.collapse(toInsets: safeAreaInsets) + : layoutMargins + safeAreaInsets + return layoutMargins } } diff --git a/SwiftMessages/MarginAdjustable.swift b/SwiftMessages/MarginAdjustable.swift index 44b0c11c..1b064bb4 100644 --- a/SwiftMessages/MarginAdjustable.swift +++ b/SwiftMessages/MarginAdjustable.swift @@ -34,19 +34,5 @@ public protocol MarginAdjustable { var collapseLayoutMarginAdditions: Bool { get set } var bounceAnimationOffset: CGFloat { get set } - - /** - Deprecated APIs - */ - - /// Top margin adjustment for status bar avoidance in pre-iOS 11+ - @available(*, deprecated, message: "Now handled by `collapseLayoutMarginAdditions`") - var statusBarOffset: CGFloat { get set } - /// Safe area top adjustment in iOS 11+ - @available(*, deprecated, message: "Use the `topLayoutMarginAddition` instead.") - var safeAreaTopOffset: CGFloat { get set } - /// Safe area bottom adjustment in iOS 11+ - @available(*, deprecated, message: "Use the `bottomLayoutMarginAddition` instead.") - var safeAreaBottomOffset: CGFloat { get set } } diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index 225d6863..c41ab216 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -193,9 +193,6 @@ extension SwiftMessagesSegue { /// A convenience method for configuring some pre-defined layouts that mirror a subset of `MessageView.Layout`. public func configure(layout: Layout) { messageView.bounceAnimationOffset = 0 - messageView.statusBarOffset = 0 - messageView.safeAreaTopOffset = 0 - messageView.safeAreaBottomOffset = 0 containment = .content containerView.cornerRadius = 0 containerView.roundsLeadingCorners = false From 91bee6b49bcb1097b63f2c28e09fc698ebebba58 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 18 May 2019 20:09:46 -0500 Subject: [PATCH 019/139] Improve view controller layout behavior on iPad --- Demo/Demo/Base.lproj/Main.storyboard | 12 +-- SwiftMessages.xcodeproj/project.pbxproj | 8 +- SwiftMessages/BaseView.swift | 94 +++++++++++++++++-- SwiftMessages/MessageView.swift | 32 ------- SwiftMessages/NSLayoutConstraint+Utils.swift | 16 ++++ SwiftMessages/SwiftMessagesSegue.swift | 33 +++++-- .../ViewControllerContainerView.swift | 35 ------- ViewControllers.md | 19 ++-- 8 files changed, 144 insertions(+), 105 deletions(-) create mode 100644 SwiftMessages/NSLayoutConstraint+Utils.swift delete mode 100644 SwiftMessages/ViewControllerContainerView.swift diff --git a/Demo/Demo/Base.lproj/Main.storyboard b/Demo/Demo/Base.lproj/Main.storyboard index 12449d96..0c6de711 100644 --- a/Demo/Demo/Base.lproj/Main.storyboard +++ b/Demo/Demo/Base.lproj/Main.storyboard @@ -1,13 +1,11 @@ - + - - - + @@ -874,7 +872,7 @@ - + @@ -97,7 +95,7 @@ - + diff --git a/SwiftMessages/Resources/TabView.xib b/SwiftMessages/Resources/TabView.xib index bd059909..ef47ea3c 100644 --- a/SwiftMessages/Resources/TabView.xib +++ b/SwiftMessages/Resources/TabView.xib @@ -1,11 +1,9 @@ - - - - + + - + @@ -31,13 +29,13 @@ - + - - + + @@ -72,19 +70,18 @@ - + @@ -108,19 +105,18 @@ - + @@ -144,19 +140,18 @@ - + @@ -179,19 +174,18 @@ - + @@ -229,7 +223,7 @@ - + @@ -309,7 +303,6 @@ @@ -343,7 +336,6 @@ @@ -377,7 +369,6 @@ @@ -410,7 +401,6 @@ @@ -447,7 +437,6 @@ @@ -481,7 +470,6 @@ @@ -516,7 +504,6 @@ @@ -549,7 +536,6 @@ @@ -580,7 +566,6 @@ @@ -610,7 +595,6 @@ @@ -640,7 +624,6 @@ @@ -658,7 +641,7 @@ @@ -672,7 +655,7 @@ @@ -691,7 +674,7 @@ @@ -705,7 +688,7 @@ @@ -930,7 +913,7 @@ - + @@ -968,7 +951,7 @@ - + @@ -976,11 +959,11 @@ - + - + - - - - + + + + @@ -931,7 +1072,7 @@ - + @@ -951,7 +1092,7 @@ - + @@ -1049,18 +1190,19 @@ - + + @@ -1084,11 +1226,17 @@ - - - - + + + + + + + + + + diff --git a/Demo/Demo/ViewControllersViewController.swift b/Demo/Demo/ViewControllersViewController.swift index f3339ebc..733dc07d 100644 --- a/Demo/Demo/ViewControllersViewController.swift +++ b/Demo/Demo/ViewControllersViewController.swift @@ -19,27 +19,39 @@ class SwiftMessagesTopSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .topMessage) + messageView.layout.size.height = .absolute(300) } } -class SwiftMessagesTopCardSegue: SwiftMessagesSegue { +class SwiftMessagesBottomSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .topCard) + configure(layout: .bottomMessage) + messageView.layout.size.height = .absolute(300) } } -class SwiftMessagesTopTabSegue: SwiftMessagesSegue { +class SwiftMessagesLeadingSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .topTab) + configure(layout: .leadingMessage) + messageView.layout.size.width = .absolute(300) } } -class SwiftMessagesBottomSegue: SwiftMessagesSegue { +class SwiftMessagesTrailingSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .bottomMessage) + configure(layout: .trailingMessage) + messageView.layout.size.width = .absolute(300) + } +} + +class SwiftMessagesTopCardSegue: SwiftMessagesSegue { + override public init(identifier: String?, source: UIViewController, destination: UIViewController) { + super.init(identifier: identifier, source: source, destination: destination) + configure(layout: .topCard) + messageView.layout.size.height = .absolute(300) } } @@ -47,7 +59,31 @@ class SwiftMessagesBottomCardSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .bottomCard) - messageView.messageSize.width = .relative(0.75, from: .superview) + messageView.layout.size.height = .absolute(300) + } +} + +class SwiftMessagesLeadingCardSegue: SwiftMessagesSegue { + override public init(identifier: String?, source: UIViewController, destination: UIViewController) { + super.init(identifier: identifier, source: source, destination: destination) + configure(layout: .leadingCard) + messageView.layout.size.width = .absolute(300) + } +} + +class SwiftMessagesTrailingCardSegue: SwiftMessagesSegue { + override public init(identifier: String?, source: UIViewController, destination: UIViewController) { + super.init(identifier: identifier, source: source, destination: destination) + configure(layout: .trailingCard) + messageView.layout.size.width = .absolute(300) + } +} + +class SwiftMessagesTopTabSegue: SwiftMessagesSegue { + override public init(identifier: String?, source: UIViewController, destination: UIViewController) { + super.init(identifier: identifier, source: source, destination: destination) + configure(layout: .topTab) + messageView.layout.size.height = .absolute(300) } } @@ -55,6 +91,23 @@ class SwiftMessagesBottomTabSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .bottomTab) + messageView.layout.size.height = .absolute(300) + } +} + +class SwiftMessagesLeadingTabSegue: SwiftMessagesSegue { + override public init(identifier: String?, source: UIViewController, destination: UIViewController) { + super.init(identifier: identifier, source: source, destination: destination) + configure(layout: .leadingTab) + messageView.layout.size.width = .absolute(300) + } +} + +class SwiftMessagesTrailingTabSegue: SwiftMessagesSegue { + override public init(identifier: String?, source: UIViewController, destination: UIViewController) { + super.init(identifier: identifier, source: source, destination: destination) + configure(layout: .trailingTab) + messageView.layout.size.width = .absolute(300) } } @@ -62,5 +115,16 @@ class SwiftMessagesCenteredSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .centered) + messageView.layout.size.height = .absolute(300) + } +} + +class SwiftMessagesOffCenteredSegue: SwiftMessagesSegue { + override public init(identifier: String?, source: UIViewController, destination: UIViewController) { + super.init(identifier: identifier, source: source, destination: destination) + configure(layout: .centered) + messageView.layout.insets.top = .absolute(0, from: .safeArea) + messageView.layout.center.x = .relative(0.33, in: .safeArea) + messageView.layout.size.height = .absolute(300) } } diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 1efdfa4c..47ac1180 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -51,8 +51,7 @@ 228DF5681FAD0806004F8A39 /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */; }; 228DF5691FAD0806004F8A39 /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5481FAD0805004F8A39 /* successIconLight.png */; }; 228DF56A1FAD0806004F8A39 /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */; }; - 2290944825D88A05002E8111 /* MessageSizeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290944725D88A05002E8111 /* MessageSizeable.swift */; }; - 2290957825D9BC9F002E8111 /* MessageSizing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290957725D9BC9F002E8111 /* MessageSizing.swift */; }; + 2290944825D88A05002E8111 /* Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290944725D88A05002E8111 /* Layout.swift */; }; 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */; }; 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; @@ -140,8 +139,7 @@ 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = infoIconSubtle.png; path = Resources/infoIconSubtle.png; sourceTree = ""; }; 228DF5481FAD0805004F8A39 /* successIconLight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = successIconLight.png; path = Resources/successIconLight.png; sourceTree = ""; }; 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; - 2290944725D88A05002E8111 /* MessageSizeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSizeable.swift; sourceTree = ""; }; - 2290957725D9BC9F002E8111 /* MessageSizing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSizing.swift; sourceTree = ""; }; + 2290944725D88A05002E8111 /* Layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Layout.swift; sourceTree = ""; }; 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILayoutPriority+Extensions.swift"; sourceTree = ""; }; 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; @@ -301,8 +299,7 @@ 8644955C1D4FAF7C0056EB2A /* WindowViewController.swift */, 867BED201D622793005212E3 /* BackgroundViewable.swift */, 864495551D4F7C390056EB2A /* Identifiable.swift */, - 2290944725D88A05002E8111 /* MessageSizeable.swift */, - 2290957725D9BC9F002E8111 /* MessageSizing.swift */, + 2290944725D88A05002E8111 /* Layout.swift */, 86AAF81D1D5549680031EE32 /* MarginAdjustable.swift */, 22E307FE1E74C5B100E35893 /* AccessibleMessage.swift */, 86AAF82A1D580DD70031EE32 /* Error.swift */, @@ -539,7 +536,7 @@ 86BBA8FC1D5E03F100FE8F16 /* MessageView.swift in Sources */, 86BBA9061D5E040C00FE8F16 /* Identifiable.swift in Sources */, 22F27951210CE25900273E7F /* CornerRoundingView.swift in Sources */, - 2290944825D88A05002E8111 /* MessageSizeable.swift in Sources */, + 2290944825D88A05002E8111 /* Layout.swift in Sources */, 86BBA9011D5E040600FE8F16 /* PassthroughWindow.swift in Sources */, 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */, 86BBA9031D5E040600FE8F16 /* UIViewController+Extensions.swift in Sources */, @@ -562,7 +559,6 @@ 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */, 86589D471D64B6E40041676C /* BaseView.swift in Sources */, 225304622290C76E00A03ACF /* NSLayoutConstraint+Extensions.swift in Sources */, - 2290957825D9BC9F002E8111 /* MessageSizing.swift in Sources */, 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */, 867BED211D622793005212E3 /* BackgroundViewable.swift in Sources */, 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */, diff --git a/SwiftMessages/Animator.swift b/SwiftMessages/Animator.swift index d3ec0af7..292ea395 100644 --- a/SwiftMessages/Animator.swift +++ b/SwiftMessages/Animator.swift @@ -45,13 +45,13 @@ public struct SafeZoneConflicts: OptionSet { public class AnimationContext { public let messageView: UIView - public let containerView: UIView & MessageSizing + public let containerView: UIView & LayoutInstalling public let safeZoneConflicts: SafeZoneConflicts public let interactiveHide: Bool internal init( messageView: UIView, - containerView: UIView & MessageSizing, + containerView: UIView & LayoutInstalling, safeZoneConflicts: SafeZoneConflicts, interactiveHide: Bool ) { diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index 2ae86a45..cdde9008 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -14,7 +14,7 @@ import UIKit of the optional SwiftMessages protocols and provides some convenience functions and a configurable tap handler. Message views do not need to inherit from `BaseVew`. */ -open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeable { +open class BaseView: UIView, BackgroundViewable, MarginAdjustable, LayoutDefining { /* MARK: - IB outlets @@ -63,6 +63,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab */ /** + TODO SIZE - update documentation A convenience function for installing a content view as a subview of `backgroundView` and pinning the edges to `backgroundView` with the specified `insets`. @@ -82,6 +83,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab } /** + TODO SIZE - update documentation - insets removed A convenience function for installing a background view and pinning to the layout margins. This is useful for creating programatic layouts where the background view needs to be inset from the message view's edges (like a card-style layout). @@ -90,7 +92,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab assigned to the `backgroundView` property. - Parameter insets: The amount to inset the content view from the margins. Default is zero inset. */ - open func installBackgroundView(_ backgroundView: UIView, insets: UIEdgeInsets = UIEdgeInsets.zero) { + open func installBackgroundView(_ backgroundView: UIView) { backgroundView.translatesAutoresizingMaskIntoConstraints = false if backgroundView != self { backgroundView.removeFromSuperview() @@ -100,65 +102,57 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab NSLayoutConstraint.activate([ backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) .with(priority: .belowMessageSizeable), - backgroundView.topAnchor.constraint( - equalTo: layoutMarginsGuide.topAnchor, - constant: insets.top - ).with(priority: .belowMessageSizeable), - backgroundView.bottomAnchor.constraint( - equalTo: layoutMarginsGuide.bottomAnchor, - constant: -insets.bottom - ).with(priority: .belowMessageSizeable), - backgroundView.heightAnchor.constraint(equalToConstant: 350) - .with(priority: UILayoutPriority(rawValue: 200)), - backgroundView.leftAnchor.constraint( - equalTo: layoutMarginsGuide.leftAnchor, - constant: insets.left - ).with(priority: .belowMessageSizeable), - backgroundView.rightAnchor.constraint( - equalTo: layoutMarginsGuide.rightAnchor, - constant: -insets.right - ).with(priority: .belowMessageSizeable), - ]) - installTapRecognizer() - } - - /** - A convenience function for installing a background view and pinning to the horizontal - layout margins and to the vertical edges. This is useful for creating programatic layouts where - the background view needs to be inset from the message view's horizontal edges (like a tab-style layout). - - - Parameter backgroundView: The view to be installed as a subview and - assigned to the `backgroundView` property. - - Parameter insets: The amount to inset the content view from the horizontal margins and vertical edges. - Default is zero inset. - */ - open func installBackgroundVerticalView(_ backgroundView: UIView, insets: UIEdgeInsets = UIEdgeInsets.zero) { - backgroundView.translatesAutoresizingMaskIntoConstraints = false - if backgroundView != self { - backgroundView.removeFromSuperview() - } - addSubview(backgroundView) - self.backgroundView = backgroundView - NSLayoutConstraint.activate([ - backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) + backgroundView.topAnchor.constraint(equalTo: topAnchor) + .with(priority: .belowMessageSizeable), + backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor) .with(priority: .belowMessageSizeable), - backgroundView.topAnchor.constraint(equalTo: topAnchor, constant: insets.top) - .with(priority: .required), - backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -insets.bottom) - .with(priority: .required), backgroundView.heightAnchor.constraint(equalToConstant: 350) .with(priority: UILayoutPriority(rawValue: 200)), - backgroundView.leftAnchor.constraint( - equalTo: layoutMarginsGuide.leftAnchor, constant: insets.left - ).with(priority: .belowMessageSizeable), - backgroundView.rightAnchor.constraint( - equalTo: layoutMarginsGuide.rightAnchor, - constant: -insets.right - ).with(priority: .belowMessageSizeable), + backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor) + .with(priority: .belowMessageSizeable), + backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor) + .with(priority: .belowMessageSizeable), ]) installTapRecognizer() } +// /** +// A convenience function for installing a background view and pinning to the horizontal +// layout margins and to the vertical edges. This is useful for creating programatic layouts where +// the background view needs to be inset from the message view's horizontal edges (like a tab-style layout). +// +// - Parameter backgroundView: The view to be installed as a subview and +// assigned to the `backgroundView` property. +// - Parameter insets: The amount to inset the content view from the horizontal margins and vertical edges. +// Default is zero inset. +// */ +// open func installBackgroundVerticalView(_ backgroundView: UIView, insets: UIEdgeInsets = UIEdgeInsets.zero) { +// backgroundView.translatesAutoresizingMaskIntoConstraints = false +// if backgroundView != self { +// backgroundView.removeFromSuperview() +// } +// addSubview(backgroundView) +// self.backgroundView = backgroundView +// NSLayoutConstraint.activate([ +// backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) +// .with(priority: .belowMessageSizeable), +// backgroundView.topAnchor.constraint(equalTo: topAnchor, constant: insets.top) +// .with(priority: .required), +// backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -insets.bottom) +// .with(priority: .required), +// backgroundView.heightAnchor.constraint(equalToConstant: 350) +// .with(priority: UILayoutPriority(rawValue: 200)), +// backgroundView.leftAnchor.constraint( +// equalTo: layoutMarginsGuide.leftAnchor, constant: insets.left +// ).with(priority: .belowMessageSizeable), +// backgroundView.rightAnchor.constraint( +// equalTo: layoutMarginsGuide.rightAnchor, +// constant: -insets.right +// ).with(priority: .belowMessageSizeable), +// ]) +// installTapRecognizer() +// } + /* MARK: - Tap handler */ @@ -203,11 +197,8 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab // MARK: - MessageSizeable - /// Configure the view's size - public var messageSize = MessageSize() - - /// Configure the view's insets from the container - public var messageInsets = MessageInsets() + /// Configure the view's layout + public var layout = Layout() /* MARK: - MarginAdjustable diff --git a/SwiftMessages/CornerRoundingView.swift b/SwiftMessages/CornerRoundingView.swift index 398b731c..7db484fb 100644 --- a/SwiftMessages/CornerRoundingView.swift +++ b/SwiftMessages/CornerRoundingView.swift @@ -24,12 +24,12 @@ open class CornerRoundingView: UIView { /// rounded. For example, the layout in TabView.xib rounds the bottom corners /// when displayed from the top and the top corners when displayed from the bottom. /// When this property is `true`, the `roundedCorners` property will be overwritten - /// by relevant animators (e.g. `TopBottomAnimation`). + /// by relevant animators (e.g. `EdgeAnimation`). @IBInspectable open var roundsLeadingCorners: Bool = false /// Specifies which corners should be rounded. When `roundsLeadingCorners = true`, relevant - /// relevant animators (e.g. `TopBottomAnimation`) will overwrite the value of this property. + /// relevant animators (e.g. `EdgeAnimation`) will overwrite the value of this property. open var roundedCorners: UIRectCorner = [.allCorners] { didSet { updateMaskPath() diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift new file mode 100644 index 00000000..4afcf7b7 --- /dev/null +++ b/SwiftMessages/Layout.swift @@ -0,0 +1,91 @@ +// +// BoundaryInsets.swift +// SwiftMessages +// +// Created by Timothy Moose on 2/13/21. +// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. +// + +import UIKit + +public protocol LayoutDefining { + var layout: Layout { get } +} + +public protocol LayoutInstalling { + func install(layoutDefiningView: LayoutDefining & UIView) +} + +public struct Layout { + + public var size = Size() + public var insets = Insets() + public var center = Center() + public var min = Layout() + public var max = Layout() + + public enum Boundary { + case superview + case safeArea + case margin + } + + public struct Size { + + public enum Dimension { + case absolute(CGFloat) + case relative(CGFloat, to: Boundary) + } + + public var width: Dimension? + public var height: Dimension? + } + + public struct Insets { + + public enum Dimension { + case absolute(CGFloat, from: Boundary) + case relative(CGFloat, from: Boundary) + } + + public var top: Dimension? + public var bottom: Dimension? + public var leading: Dimension? + public var trailing: Dimension? + } + + public struct Center { + + public enum Dimension { + case absolute(CGFloat, in: Boundary) + case relative(CGFloat, in: Boundary) + } + + public var x: Dimension? + public var y: Dimension? + } + + public struct Layout { + public var size = Size() + public var insets = Insets() + public var center = Center() + } +} + +extension Layout.Insets.Dimension { + var boundary: Layout.Boundary { + switch self { + case .absolute(_, let boundary): return boundary + case .relative(_, let boundary): return boundary + } + } +} + +extension Layout.Center.Dimension { + var boundary: Layout.Boundary { + switch self { + case .absolute(_, let boundary): return boundary + case .relative(_, let boundary): return boundary + } + } +} diff --git a/SwiftMessages/MaskingView.swift b/SwiftMessages/MaskingView.swift index 889ac9de..81301994 100644 --- a/SwiftMessages/MaskingView.swift +++ b/SwiftMessages/MaskingView.swift @@ -24,13 +24,13 @@ import UIKit // .with(priority: UILayoutPriority(rawValue: 200)), // ] -class MaskingView: PassthroughView, MessageSizing { +class MaskingView: PassthroughView, LayoutInstalling { - func install(sizeableView: MessageSizeable & UIView) { - self.sizeableView?.removeFromSuperview() - self.sizeableView = sizeableView - sizeableView.translatesAutoresizingMaskIntoConstraints = false - addSubview(sizeableView) + func install(layoutDefiningView: UIView & LayoutDefining) { + self.layoutDefiningView?.removeFromSuperview() + self.layoutDefiningView = layoutDefiningView + layoutDefiningView.translatesAutoresizingMaskIntoConstraints = false + addSubview(layoutDefiningView) setNeedsUpdateConstraints() } @@ -96,7 +96,7 @@ class MaskingView: PassthroughView, MessageSizing { private var keyboardTrackingView: KeyboardTrackingView? private var cachedConstraints: [NSLayoutConstraint] = [] private let messageInsetsGuide = UILayoutGuide() - private var sizeableView: (MessageSizeable & UIView)? + private var layoutDefiningView: (LayoutDefining & UIView)? override func addSubview(_ view: UIView) { super.addSubview(view) @@ -110,20 +110,35 @@ class MaskingView: PassthroughView, MessageSizing { super.updateConstraints() NSLayoutConstraint.deactivate(cachedConstraints) cachedConstraints = [] - if let top = sizeableView?.messageInsets.top { update(top: top) } - if let bottom = sizeableView?.messageInsets.bottom { update(bottom: bottom) } - if let leading = sizeableView?.messageInsets.leading { update(leading: leading) } - if let trailing = sizeableView?.messageInsets.trailing { update(trailing: trailing) } - if let sizeableView = sizeableView { update(sizeableView: sizeableView) } + if let layoutDefiningView = layoutDefiningView { + let layout = layoutDefiningView.layout + add(insets: layout.insets, relation: .equal) + add(insets: layout.min.insets, relation: .min) + add(insets: layout.max.insets, relation: .max) + add(layoutDefiningView: layoutDefiningView) + } NSLayoutConstraint.activate(cachedConstraints) } - private func update(top: MessageInsets.Dimension) { + private enum ConstraintRelation { + case equal + case min + case max + } + + private func add(insets: Layout.Insets, relation: ConstraintRelation) { + if let top = insets.top { add(top: top, relation: relation) } + if let bottom = insets.bottom { add(bottom: bottom, relation: relation) } + if let leading = insets.leading { add(leading: leading, relation: relation) } + if let trailing = insets.trailing { add(trailing: trailing, relation: relation) } + } + + private func add(top: Layout.Insets.Dimension, relation: ConstraintRelation) { let length: CGFloat switch top { - case .absoluteMargin(let dimension, _): + case .absolute(let dimension, _): length = dimension - case .relativeMargin(let percentage, _): + case .relative(let percentage, _): length = bounds.height * percentage } let otherAnchor: NSLayoutYAxisAnchor @@ -137,18 +152,20 @@ class MaskingView: PassthroughView, MessageSizing { otherAnchor = layoutMarginsGuide.topAnchor } } - cachedConstraints.append( - messageInsetsGuide.topAnchor.constraint(equalTo: otherAnchor, constant: length) - .with(priority: .messageInset) + add( + anchor: messageInsetsGuide.topAnchor, + otherAnchor: otherAnchor, + constant: length, + relation: relation ) } - private func update(bottom: MessageInsets.Dimension) { + private func add(bottom: Layout.Insets.Dimension, relation: ConstraintRelation) { let length: CGFloat switch bottom { - case .absoluteMargin(let dimension, _): + case .absolute(let dimension, _): length = dimension - case .relativeMargin(let percentage, _): + case .relative(let percentage, _): length = bounds.height * percentage } let otherAnchor: NSLayoutYAxisAnchor @@ -162,18 +179,20 @@ class MaskingView: PassthroughView, MessageSizing { otherAnchor = layoutMarginsGuide.bottomAnchor } } - cachedConstraints.append( - messageInsetsGuide.bottomAnchor.constraint(equalTo: otherAnchor, constant: -length) - .with(priority: .messageInset) + add( + anchor: otherAnchor, + otherAnchor: messageInsetsGuide.bottomAnchor, + constant: length, + relation: relation ) } - private func update(leading: MessageInsets.Dimension) { + private func add(leading: Layout.Insets.Dimension, relation: ConstraintRelation) { let length: CGFloat switch leading { - case .absoluteMargin(let dimension, _): + case .absolute(let dimension, _): length = dimension - case .relativeMargin(let percentage, _): + case .relative(let percentage, _): length = bounds.width * percentage } let otherAnchor: NSLayoutXAxisAnchor @@ -187,18 +206,20 @@ class MaskingView: PassthroughView, MessageSizing { otherAnchor = layoutMarginsGuide.leadingAnchor } } - cachedConstraints.append( - messageInsetsGuide.leadingAnchor.constraint(equalTo: otherAnchor, constant: length) - .with(priority: .messageInset) + add( + anchor: messageInsetsGuide.leadingAnchor, + otherAnchor: otherAnchor, + constant: length, + relation: relation ) } - private func update(trailing: MessageInsets.Dimension) { + private func add(trailing: Layout.Insets.Dimension, relation: ConstraintRelation) { let length: CGFloat switch trailing { - case .absoluteMargin(let dimension, _): + case .absolute(let dimension, _): length = dimension - case .relativeMargin(let percentage, _): + case .relative(let percentage, _): length = bounds.width * percentage } let otherAnchor: NSLayoutXAxisAnchor @@ -212,55 +233,193 @@ class MaskingView: PassthroughView, MessageSizing { otherAnchor = layoutMarginsGuide.trailingAnchor } } - cachedConstraints.append( - messageInsetsGuide.trailingAnchor.constraint(equalTo: otherAnchor, constant: -length) - .with(priority: .messageInset) + add( + anchor: otherAnchor, + otherAnchor: messageInsetsGuide.trailingAnchor, + constant: length, + relation: relation ) } - private func update(sizeableView view: MessageSizeable & UIView) { + private func add( + anchor: NSLayoutXAxisAnchor, + otherAnchor: NSLayoutXAxisAnchor, + constant: CGFloat, + relation: ConstraintRelation + ) { + let constraint: NSLayoutConstraint + switch relation { + case .equal: + constraint = anchor + .constraint(equalTo: otherAnchor, constant: constant) + .with(priority: .messageInsets) + case .min: + constraint = anchor + .constraint(greaterThanOrEqualTo: otherAnchor, constant: constant) + .with(priority: .messageInsetsBounds) + case .max: + constraint = anchor + .constraint(lessThanOrEqualTo: otherAnchor, constant: constant) + .with(priority: .messageInsetsBounds) + } + cachedConstraints.append(constraint) + } + + private func add( + anchor: NSLayoutYAxisAnchor, + otherAnchor: NSLayoutYAxisAnchor, + constant: CGFloat, + relation: ConstraintRelation + ) { + let constraint: NSLayoutConstraint + switch relation { + case .equal: + constraint = anchor + .constraint(equalTo: otherAnchor, constant: constant) + .with(priority: .messageInsets) + case .min: + constraint = anchor + .constraint(greaterThanOrEqualTo: otherAnchor, constant: constant) + .with(priority: .messageInsetsBounds) + case .max: + constraint = anchor + .constraint(lessThanOrEqualTo: otherAnchor, constant: constant) + .with(priority: .messageInsetsBounds) + } + cachedConstraints.append(constraint) + } + + private func add(layoutDefiningView view: LayoutDefining & UIView) { cachedConstraints += [ messageInsetsGuide.topAnchor.constraint(equalTo: view.topAnchor), messageInsetsGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor), messageInsetsGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor), messageInsetsGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor), ] - if let width = view.messageSize.width { - let length = self.length(for: width, extractor: { $0.width }) - cachedConstraints.append( - view.widthAnchor.constraint(equalToConstant: length) + add(layoutDefiningView: view, size: view.layout.size, relation: .equal) + add(layoutDefiningView: view, size: view.layout.min.size, relation: .min) + add(layoutDefiningView: view, size: view.layout.max.size, relation: .max) + add(layoutDefiningView: view, center: view.layout.center, relation: .equal) + add(layoutDefiningView: view, center: view.layout.min.center, relation: .min) + add(layoutDefiningView: view, center: view.layout.max.center, relation: .max) + } + + private func add( + layoutDefiningView view: LayoutDefining & UIView, + size: Layout.Size, + relation: ConstraintRelation + ) { + if let width = size.width { + let length = self.length(for: width) { $0.width } + let constraint: NSLayoutConstraint + switch relation { + case .equal: + constraint = view.widthAnchor.constraint(equalToConstant: length) .with(priority: .messageSize) - ) + case .min: + constraint = view.widthAnchor.constraint(greaterThanOrEqualToConstant: length) + .with(priority: .messageSizeBounds) + case .max: + constraint = view.widthAnchor.constraint(lessThanOrEqualToConstant: length) + .with(priority: .messageSizeBounds) + } + cachedConstraints.append(constraint) } - if let height = view.messageSize.height { - let length = self.length(for: height, extractor: { $0.height }) - cachedConstraints.append( - view.heightAnchor.constraint(equalToConstant: length) + if let height = size.height { + let length = self.length(for: height) { $0.height } + let constraint: NSLayoutConstraint + switch relation { + case .equal: + constraint = view.heightAnchor.constraint(equalToConstant: length) .with(priority: .messageSize) - ) + case .min: + constraint = view.heightAnchor.constraint(greaterThanOrEqualToConstant: length) + .with(priority: .messageSizeBounds) + case .max: + constraint = view.heightAnchor.constraint(lessThanOrEqualToConstant: length) + .with(priority: .messageSizeBounds) + } + cachedConstraints.append(constraint) + } + } + + + private func add( + layoutDefiningView view: LayoutDefining & UIView, + center: Layout.Center, + relation: ConstraintRelation + ) { + if let x = center.x { + let length = self.length(for: x) { ($0.minX, $0.maxX) } + let otherAnchor: NSLayoutXAxisAnchor + switch x.boundary { + case .superview: otherAnchor = leadingAnchor + case .margin: otherAnchor = layoutMarginsGuide.leadingAnchor + case .safeArea: + if #available(iOS 11.0, *) { + otherAnchor = safeAreaLayoutGuide.leadingAnchor + } else { + otherAnchor = layoutMarginsGuide.leadingAnchor + } + } + let constraint: NSLayoutConstraint + switch relation { + case .equal: + constraint = view.centerXAnchor.constraint(equalTo: otherAnchor, constant: length) + .with(priority: .messageCenter) + case .min: + constraint = view.centerXAnchor.constraint( + greaterThanOrEqualTo: otherAnchor, + constant: length + ).with(priority: .messageSizeBounds) + case .max: + constraint = view.centerXAnchor.constraint( + lessThanOrEqualTo: otherAnchor, + constant: length + ).with(priority: .messageSizeBounds) + } + cachedConstraints.append(constraint) + } + if let y = center.y { + let length = self.length(for: y) { ($0.minY, $0.maxY) } + let otherAnchor: NSLayoutYAxisAnchor + switch y.boundary { + case .superview: otherAnchor = topAnchor + case .margin: otherAnchor = layoutMarginsGuide.topAnchor + case .safeArea: + if #available(iOS 11.0, *) { + otherAnchor = safeAreaLayoutGuide.topAnchor + } else { + otherAnchor = layoutMarginsGuide.topAnchor + } + } + let constraint: NSLayoutConstraint + switch relation { + case .equal: + constraint = view.centerYAnchor.constraint(equalTo: otherAnchor, constant: length) + .with(priority: .messageCenter) + case .min: + constraint = view.centerYAnchor.constraint( + greaterThanOrEqualTo: otherAnchor, + constant: length + ).with(priority: .messageSizeBounds) + case .max: + constraint = view.centerYAnchor.constraint( + lessThanOrEqualTo: otherAnchor, + constant: length + ).with(priority: .messageSizeBounds) + } + cachedConstraints.append(constraint) } } private func length( - for dimension: MessageSize.Dimension, + for dimension: Layout.Size.Dimension, extractor: (CGRect) -> CGFloat ) -> CGFloat { switch dimension { case .absolute(let dimension): return dimension - case .absoluteMargin(let margin, let boundary): - let insets: UIEdgeInsets - switch boundary { - case .superview: insets = .zero - case .margin: insets = layoutMargins - case .safeArea: - if #available(iOS 11.0, *) { - insets = safeAreaInsets - } else { - insets = layoutMargins - } - } - return extractor(bounds.inset(by: insets)) - margin * 2 case .relative(let percentage, let boundary): let insets: UIEdgeInsets switch boundary { @@ -276,4 +435,30 @@ class MaskingView: PassthroughView, MessageSizing { return extractor(bounds.inset(by: insets)) * percentage } } + + private func length( + for dimension: Layout.Center.Dimension, + extractor: (CGRect) -> (CGFloat, CGFloat) + ) -> CGFloat { + let insets: UIEdgeInsets + switch dimension.boundary { + case .superview: insets = .zero + case .margin: insets = layoutMargins + case .safeArea: + if #available(iOS 11.0, *) { + insets = safeAreaInsets + } else { + insets = layoutMargins + } + } + let insetBounds = bounds.inset(by: insets) + switch dimension { + case .absolute(let dimension, _): + let (min, _) = extractor(insetBounds) + return min + dimension + case .relative(let percentage, _): + let (min, max) = extractor(insetBounds) + return min + (max - min) * percentage + } + } } diff --git a/SwiftMessages/MessageSizeable.swift b/SwiftMessages/MessageSizeable.swift deleted file mode 100644 index 662f1839..00000000 --- a/SwiftMessages/MessageSizeable.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// BoundaryInsets.swift -// SwiftMessages -// -// Created by Timothy Moose on 2/13/21. -// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. -// - -import UIKit - -public protocol MessageSizeable { - var messageSize: MessageSize { get } - var messageInsets: MessageInsets { get } -} - -public enum MessageBoundary { - case superview - case safeArea - case margin -} - -/// Insets used for specifying view sizing options in terms of insets from the containing superview or safe area. -public struct MessageInsets { - - public enum Dimension { - - /// Dimension should maintain an absolute margin to the given container boundary. - case absoluteMargin(CGFloat, from: MessageBoundary) - - /// Dimension should maintain a relative margin to the given container boundary. - case relativeMargin(CGFloat, from: MessageBoundary) - } - - public var top: Dimension? - public var bottom: Dimension? - public var leading: Dimension? - public var trailing: Dimension? -} - -public struct MessageSize { - - public enum Dimension { - - /// Dimensions should be an absolute length - case absolute(CGFloat) - - /// Dimension should maintain an absolute length to the given container boundary. - case absoluteMargin(CGFloat, from: MessageBoundary) - - /// Dimension should maintain a relative margin to the given boundary. - case relative(CGFloat, from: MessageBoundary) - } - - public var width: Dimension? - public var height: Dimension? -} - -extension MessageInsets.Dimension { - var boundary: MessageBoundary { - switch self { - case .absoluteMargin(_, let boundary): return boundary - case .relativeMargin(_, let boundary): return boundary - } - } -} diff --git a/SwiftMessages/MessageSizing.swift b/SwiftMessages/MessageSizing.swift deleted file mode 100644 index b4c47dd3..00000000 --- a/SwiftMessages/MessageSizing.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// MessageSizing.swift -// SwiftMessages -// -// Created by Timothy Moose on 2/14/21. -// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. -// - -import Foundation - -public protocol MessageSizing { - func install(sizeableView: MessageSizeable & UIView) -} diff --git a/SwiftMessages/PhysicsAnimation.swift b/SwiftMessages/PhysicsAnimation.swift index 0fb976c5..46f3d1ef 100644 --- a/SwiftMessages/PhysicsAnimation.swift +++ b/SwiftMessages/PhysicsAnimation.swift @@ -70,18 +70,41 @@ public class PhysicsAnimation: NSObject, Animator { messageView = view containerView = container self.context = context - view.translatesAutoresizingMaskIntoConstraints = false - container.addSubview(view) + if let layoutDefiningView = view as? LayoutDefining & UIView { + container.install(layoutDefiningView: layoutDefiningView) + } else { + view.translatesAutoresizingMaskIntoConstraints = false + container.addSubview(view) + } switch placement { case .center: - view.centerYAnchor.constraint(equalTo: container.centerYAnchor).with(priority: UILayoutPriority(200)).isActive = true + view.centerYAnchor.constraint(equalTo: container.centerYAnchor) + .with(priority: UILayoutPriority(200)).isActive = true case .top: - view.topAnchor.constraint(equalTo: container.topAnchor).with(priority: UILayoutPriority(200)).isActive = true + view.topAnchor.constraint(equalTo: container.topAnchor) + .with(priority: UILayoutPriority(200)).isActive = true case .bottom: - view.bottomAnchor.constraint(equalTo: container.bottomAnchor).with(priority: UILayoutPriority(200)).isActive = true + view.bottomAnchor.constraint(equalTo: container.bottomAnchor) + .with(priority: UILayoutPriority(200)).isActive = true } - NSLayoutConstraint(item: view, attribute: .leading, relatedBy: .equal, toItem: container, attribute: .leading, multiplier: 1, constant: 0).isActive = true - NSLayoutConstraint(item: view, attribute: .trailing, relatedBy: .equal, toItem: container, attribute: .trailing, multiplier: 1, constant: 0).isActive = true + NSLayoutConstraint( + item: view, + attribute: .leading, + relatedBy: .equal, + toItem: container, + attribute: .leading, + multiplier: 1, + constant: 0 + ).with(priority: .belowMessageSizeable).isActive = true + NSLayoutConstraint( + item: view, + attribute: .trailing, + relatedBy: .equal, + toItem: container, + attribute: .trailing, + multiplier: 1, + constant: 0 + ).with(priority: .belowMessageSizeable).isActive = true // Important to layout now in order to get the right safe area insets container.layoutIfNeeded() adjustMargins() diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index e16c076e..25fc11c7 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -105,9 +105,9 @@ class Presenter: NSObject { private static func animator(forPresentationStyle style: SwiftMessages.PresentationStyle, delegate: AnimationDelegate) -> Animator { switch style { case .top: - return TopBottomAnimation(style: .top, delegate: delegate) + return EdgeAnimation(style: .top, delegate: delegate) case .bottom: - return TopBottomAnimation(style: .bottom, delegate: delegate) + return EdgeAnimation(style: .bottom, delegate: delegate) case .center: return PhysicsAnimation(delegate: delegate) case .custom(let animator): diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index f20491bc..8013ccd0 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -69,60 +69,50 @@ import UIKit open class SwiftMessagesSegue: UIStoryboardSegue { /** - Specifies one of the pre-defined layouts, mirroring a subset of `MessageView.Layout`. + Specifies one of the pre-defined layout configurations. */ public enum Layout { - /// The standard message view layout on top. + /// The standard message view layout that slides down from the top edge. case topMessage - /// The standard message view layout on bottom. + /// The standard message view layout that slides up from the bottom edge. case bottomMessage - /// A floating card-style view with rounded corners on top - case topCard + /// The standard message view layout that slides in from the leading edge. + case leadingMessage - /// A floating tab-style view with rounded corners on bottom - case topTab + /// The standard message view layout that slides in from the trailing edge. + case trailingMessage - /// A floating card-style view with rounded corners on bottom + /// A floating card-style view with rounded corners that slides down from the top edge. + case topCard + + /// A floating card-style view with rounded corners that slides up from the bottom edge. case bottomCard - /// A floating tab-style view with rounded corners on top + /// A floating card-style view with rounded corners that slides in from the leading edge. + case leadingCard + + /// A floating card-style view with rounded corners that slides in from the trailing edge. + case trailingCard + + /// A floating tab-style view with rounded leading corners that slides down from the top edge. + case topTab + + /// A floating tab-style view with rounded leading corners that slides up from the bottom edge. case bottomTab + /// A floating tab-style view with rounded leading corners that slides in from the leading edge. + case leadingTab + + /// A floating tab-style view with rounded leading corners that slides in from the traling edge. + case trailingTab + /// A floating card-style view typically used with `.center` presentation style. case centered } - /** - Specifies how the view controller's view is installed into the - containing message view. - */ - public enum Containment { - - /** - The view controller's view is installed for edge-to-edge display, extending into the safe areas - to the device edges. This is done by calling `messageView.installContentView(:insets:)` - See that method's documentation for additional details. - */ - case content - - /** - The view controller's view is installed for card-style layouts, inset from the margins - and avoiding safe areas. This is done by calling `messageView.installBackgroundView(:insets:)`. - See that method's documentation for details. - */ - case background - - /** - The view controller's view is installed for tab-style layouts, inset from the side margins, but extending - to the device edge on the top or bottom. This is done by calling `messageView.installBackgroundVerticalView(:insets:)`. - See that method's documentation for details. - */ - case backgroundVertical - } - /// The presentation style to use. See the SwiftMessages.PresentationStyle for details. public var presentationStyle: SwiftMessages.PresentationStyle { get { return messenger.defaultConfig.presentationStyle } @@ -174,17 +164,11 @@ open class SwiftMessagesSegue: UIStoryboardSegue { /** The view controller's view is embedded in `containerView` before being installed into - `messageView`. This view provides configurable squircle (round) corners (see the parent + `messageView`. This view provides configurable continuous rounded corners (see the parent class `CornerRoundingView`). */ public var containerView: CornerRoundingView = CornerRoundingView() - /** - Specifies how the view controller's view is installed into the - containing message view. See `Containment` for details. - */ - public var containment: Containment = .content - /** Supply an instance of `KeyboardTrackingView` to have the message view avoid the keyboard. */ @@ -228,57 +212,130 @@ extension SwiftMessagesSegue { /// A convenience method for configuring some pre-defined layouts that mirror a subset of `MessageView.Layout`. public func configure(layout: Layout) { messageView.bounceAnimationOffset = 0 - containment = .content containerView.cornerRadius = 0 containerView.roundsLeadingCorners = false messageView.configureDropShadow() switch layout { case .topMessage: - messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) - messageView.collapseLayoutMarginAdditions = false - let animation = TopBottomAnimation(style: .top) +// TODO SIZE are these layout margin settings still relevant? +// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) +// messageView.collapseLayoutMarginAdditions = false + let animation = EdgeAnimation(style: .top) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .bottomMessage: - messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) - messageView.collapseLayoutMarginAdditions = false - let animation = TopBottomAnimation(style: .bottom) +// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) +// messageView.collapseLayoutMarginAdditions = false + let animation = EdgeAnimation(style: .bottom) + animation.springDamping = 1 + presentationStyle = .custom(animator: animation) + case .leadingMessage: +// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) +// messageView.collapseLayoutMarginAdditions = false + let animation = EdgeAnimation(style: .leading) + animation.springDamping = 1 + presentationStyle = .custom(animator: animation) + case .trailingMessage: +// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) +// messageView.collapseLayoutMarginAdditions = false + let animation = EdgeAnimation(style: .trailing) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .topCard: - containment = .background - messageView.layoutMarginAdditions = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) - messageView.collapseLayoutMarginAdditions = true + messageView.layout.insets.top = .absolute(0, from: .safeArea) + messageView.layout.insets.leading = .absolute(0, from: .safeArea) + messageView.layout.insets.trailing = .absolute(0, from: .safeArea) + messageView.layout.min.insets.top = .absolute(10, from: .superview) + messageView.layout.min.insets.leading = .absolute(10, from: .superview) + messageView.layout.min.insets.trailing = .absolute(10, from: .superview) + messageView.layout.min.insets.bottom = .absolute(10, from: .safeArea) containerView.cornerRadius = 15 presentationStyle = .top case .bottomCard: - containment = .background - messageView.layoutMarginAdditions = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) - messageView.collapseLayoutMarginAdditions = true + messageView.layout.insets.bottom = .absolute(0, from: .safeArea) + messageView.layout.insets.leading = .absolute(0, from: .safeArea) + messageView.layout.insets.trailing = .absolute(0, from: .safeArea) + messageView.layout.min.insets.bottom = .absolute(10, from: .superview) + messageView.layout.min.insets.leading = .absolute(10, from: .superview) + messageView.layout.min.insets.trailing = .absolute(10, from: .superview) + messageView.layout.min.insets.top = .absolute(10, from: .safeArea) containerView.cornerRadius = 15 presentationStyle = .bottom + case .leadingCard: + messageView.layout.insets.leading = .absolute(0, from: .safeArea) + messageView.layout.insets.top = .absolute(0, from: .safeArea) + messageView.layout.insets.bottom = .absolute(0, from: .safeArea) + messageView.layout.min.insets.leading = .absolute(10, from: .superview) + messageView.layout.min.insets.top = .absolute(10, from: .superview) + messageView.layout.min.insets.bottom = .absolute(10, from: .superview) + messageView.layout.min.insets.trailing = .absolute(10, from: .safeArea) + containerView.cornerRadius = 15 + let animation = EdgeAnimation(style: .leading) + presentationStyle = .custom(animator: animation) + case .trailingCard: + messageView.layout.insets.trailing = .absolute(0, from: .safeArea) + messageView.layout.insets.top = .absolute(0, from: .safeArea) + messageView.layout.insets.bottom = .absolute(0, from: .safeArea) + messageView.layout.min.insets.trailing = .absolute(10, from: .superview) + messageView.layout.min.insets.top = .absolute(10, from: .superview) + messageView.layout.min.insets.bottom = .absolute(10, from: .superview) + messageView.layout.min.insets.leading = .absolute(10, from: .safeArea) + containerView.cornerRadius = 15 + let animation = EdgeAnimation(style: .trailing) + presentationStyle = .custom(animator: animation) case .topTab: - containment = .backgroundVertical - messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 10, bottom: 20, right: 10) - messageView.collapseLayoutMarginAdditions = true + messageView.layout.insets.top = .absolute(0, from: .superview) + messageView.layout.insets.leading = .absolute(0, from: .safeArea) + messageView.layout.insets.trailing = .absolute(0, from: .safeArea) + messageView.layout.min.insets.leading = .absolute(10, from: .superview) + messageView.layout.min.insets.trailing = .absolute(10, from: .superview) + messageView.layout.min.insets.bottom = .absolute(10, from: .safeArea) containerView.cornerRadius = 15 containerView.roundsLeadingCorners = true - let animation = TopBottomAnimation(style: .top) + let animation = EdgeAnimation(style: .top) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .bottomTab: - containment = .backgroundVertical - messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 10, bottom: 20, right: 10) - messageView.collapseLayoutMarginAdditions = true + messageView.layout.insets.bottom = .absolute(0, from: .superview) + messageView.layout.insets.leading = .absolute(0, from: .safeArea) + messageView.layout.insets.trailing = .absolute(0, from: .safeArea) + messageView.layout.min.insets.leading = .absolute(10, from: .superview) + messageView.layout.min.insets.trailing = .absolute(10, from: .superview) + messageView.layout.min.insets.top = .absolute(10, from: .safeArea) containerView.cornerRadius = 15 containerView.roundsLeadingCorners = true - let animation = TopBottomAnimation(style: .bottom) + let animation = EdgeAnimation(style: .bottom) + animation.springDamping = 1 + presentationStyle = .custom(animator: animation) + case .leadingTab: + messageView.layout.insets.leading = .absolute(0, from: .superview) + messageView.layout.insets.top = .absolute(0, from: .safeArea) + messageView.layout.insets.bottom = .absolute(0, from: .safeArea) + messageView.layout.min.insets.top = .absolute(10, from: .superview) + messageView.layout.min.insets.bottom = .absolute(10, from: .superview) + messageView.layout.min.insets.trailing = .absolute(10, from: .safeArea) + containerView.cornerRadius = 15 + containerView.roundsLeadingCorners = true + let animation = EdgeAnimation(style: .leading) + animation.springDamping = 1 + presentationStyle = .custom(animator: animation) + case .trailingTab: + messageView.layout.insets.trailing = .absolute(0, from: .superview) + messageView.layout.insets.top = .absolute(0, from: .safeArea) + messageView.layout.insets.bottom = .absolute(0, from: .safeArea) + messageView.layout.min.insets.top = .absolute(10, from: .superview) + messageView.layout.min.insets.bottom = .absolute(10, from: .superview) + messageView.layout.min.insets.leading = .absolute(10, from: .safeArea) + containerView.cornerRadius = 15 + containerView.roundsLeadingCorners = true + let animation = EdgeAnimation(style: .trailing) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .centered: - containment = .background - messageView.layoutMarginAdditions = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) - messageView.collapseLayoutMarginAdditions = true + messageView.layout.min.insets.top = .absolute(10, from: .safeArea) + messageView.layout.min.insets.bottom = .absolute(10, from: .safeArea) + messageView.layout.min.insets.leading = .absolute(10, from: .safeArea) + messageView.layout.min.insets.trailing = .absolute(10, from: .safeArea) containerView.cornerRadius = 15 presentationStyle = .center } @@ -343,21 +400,12 @@ extension SwiftMessagesSegue { } completeTransition = transitionContext.completeTransition let transitionContainer = transitionContext.containerView - toView.translatesAutoresizingMaskIntoConstraints = false - segue.containerView.addSubview(toView) - segue.containerView.topAnchor.constraint(equalTo: toView.topAnchor).isActive = true - segue.containerView.bottomAnchor.constraint(equalTo: toView.bottomAnchor).isActive = true - segue.containerView.leadingAnchor.constraint(equalTo: toView.leadingAnchor).isActive = true - segue.containerView.trailingAnchor.constraint(equalTo: toView.trailingAnchor).isActive = true - // Install the `toView` into the message view. - switch segue.containment { - case .content: - segue.messageView.installContentView(segue.containerView) - case .background: + // Install the background and content views + do { segue.messageView.installBackgroundView(segue.containerView) - case .backgroundVertical: - segue.messageView.installBackgroundVerticalView(segue.containerView) + segue.messageView.installContentView(toView) } + let toVC = transitionContext.viewController(forKey: .to) // Nav controller automatically includes height of nav bar in, diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index 0a91fc3f..f8afc781 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -8,19 +8,22 @@ import UIKit -public class TopBottomAnimation: NSObject, Animator { +@available(*, deprecated, message: "Class renamed to `EdgeAnimation` to reflect new ability to do leading and trailing animations.") +public typealias TopBottomAnimation = EdgeAnimation + +public class EdgeAnimation: NSObject, Animator { public enum Style { case top case bottom + case leading + case trailing } public weak var delegate: AnimationDelegate? public let style: Style - open var heightDimension: Dimension? - open var showDuration: TimeInterval = 0.4 open var hideDuration: TimeInterval = 0.2 @@ -68,6 +71,10 @@ public class TopBottomAnimation: NSObject, Animator { view.transform = CGAffineTransform(translationX: 0, y: -view.frame.height) case .bottom: view.transform = CGAffineTransform(translationX: 0, y: view.frame.maxY + view.frame.height) + case .leading: // TODO SIZE do proper leading and trailing + view.transform = CGAffineTransform(translationX: -view.frame.width, y: 0) + case .trailing: + view.transform = CGAffineTransform(translationX: view.frame.maxX + view.frame.width, y: 0) } }, completion: { completed in #if SWIFTMESSAGES_APP_EXTENSIONS @@ -88,41 +95,66 @@ public class TopBottomAnimation: NSObject, Animator { if let adjustable = context.messageView as? MarginAdjustable { bounceOffset = adjustable.bounceAnimationOffset } - if let sizeableView = view as? MessageSizeable & UIView { - container.install(sizeableView: sizeableView) + if let layoutDefiningView = view as? LayoutDefining & UIView { + container.install(layoutDefiningView: layoutDefiningView) } else { view.translatesAutoresizingMaskIntoConstraints = false container.addSubview(view) } // Horizontal constraints do { - view.leadingAnchor.constraint(equalTo: container.leadingAnchor) - .with(priority: .belowMessageSizeable - 1) - .isActive = true - view.centerXAnchor.constraint(equalTo: container.centerXAnchor) - .with(priority: .belowMessageSizeable) - .isActive = true } switch style { case .top: - view.topAnchor.constraint(equalTo: container.topAnchor, constant: -bounceOffset) - .with(priority: .belowMessageSizeable) - .isActive = true + NSLayoutConstraint.activate([ + view.leadingAnchor.constraint(equalTo: container.leadingAnchor) + .with(priority: .belowMessageSizeable - 1), + view.centerXAnchor.constraint(equalTo: container.centerXAnchor) + .with(priority: .belowMessageSizeable), + view.topAnchor.constraint(equalTo: container.topAnchor, constant: -bounceOffset) + .with(priority: .belowMessageSizeable) + ]) case .bottom: - view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: bounceOffset) - .with(priority: .belowMessageSizeable) - .isActive = true + NSLayoutConstraint.activate([ + view.leadingAnchor.constraint(equalTo: container.leadingAnchor) + .with(priority: .belowMessageSizeable - 1), + view.centerXAnchor.constraint(equalTo: container.centerXAnchor) + .with(priority: .belowMessageSizeable), + view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: bounceOffset) + .with(priority: .belowMessageSizeable) + ]) + case .leading: + NSLayoutConstraint.activate([ + view.topAnchor.constraint(equalTo: container.topAnchor) + .with(priority: .belowMessageSizeable - 1), + view.centerYAnchor.constraint(equalTo: container.centerYAnchor) + .with(priority: .belowMessageSizeable), + view.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: -bounceOffset) + .with(priority: .belowMessageSizeable) + ]) + case .trailing: + NSLayoutConstraint.activate([ + view.topAnchor.constraint(equalTo: container.topAnchor) + .with(priority: .belowMessageSizeable - 1), + view.centerYAnchor.constraint(equalTo: container.centerYAnchor) + .with(priority: .belowMessageSizeable), + view.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: bounceOffset) + .with(priority: .belowMessageSizeable) + ]) } // Important to layout now in order to get the right safe area insets container.layoutIfNeeded() adjustMargins() container.layoutIfNeeded() - let animationDistance = view.frame.height switch style { case .top: - view.transform = CGAffineTransform(translationX: 0, y: -animationDistance) + view.transform = CGAffineTransform(translationX: 0, y: -view.frame.height) case .bottom: - view.transform = CGAffineTransform(translationX: 0, y: animationDistance) + view.transform = CGAffineTransform(translationX: 0, y: view.frame.height) + case .leading: + view.transform = CGAffineTransform(translationX: -view.frame.width, y: 0) + case .trailing: + view.transform = CGAffineTransform(translationX: view.frame.width, y: 0) } if context.interactiveHide { if let view = view as? BackgroundViewable { @@ -139,6 +171,10 @@ public class TopBottomAnimation: NSObject, Animator { cornerRoundingView.roundedCorners = [.bottomLeft, .bottomRight] case .bottom: cornerRoundingView.roundedCorners = [.topLeft, .topRight] + case .leading: + cornerRoundingView.roundedCorners = [.topRight, .bottomRight] + case .trailing: + cornerRoundingView.roundedCorners = [.topLeft, .bottomLeft] } } } @@ -156,6 +192,10 @@ public class TopBottomAnimation: NSObject, Animator { layoutMargins.top += bounceOffset case .bottom: layoutMargins.bottom += bounceOffset + case .leading: + layoutMargins.left += bounceOffset + case .trailing: + layoutMargins.right += bounceOffset } adjustable.layoutMargins = layoutMargins } @@ -191,21 +231,39 @@ public class TopBottomAnimation: NSObject, Animator { fileprivate var rubberBanding = false fileprivate var closeSpeed: CGFloat = 0.0 fileprivate var closePercent: CGFloat = 0.0 - fileprivate var panTranslationY: CGFloat = 0.0 + fileprivate var panTranslation: CGFloat = 0.0 @objc func pan(_ pan: UIPanGestureRecognizer) { switch pan.state { case .changed: guard let view = messageView else { return } - let height = view.bounds.height - bounceOffset - if height <= 0 { return } + let length: CGFloat + switch style { + case .top, .bottom: + length = view.bounds.height - bounceOffset + case .leading, .trailing: + length = view.bounds.width - bounceOffset + } + if length <= 0 { return } var velocity = pan.velocity(in: view) var translation = pan.translation(in: view) - if case .top = style { + switch style { + case .top: velocity.y *= -1.0 translation.y *= -1.0 + case .leading: + velocity.x *= -1.0 + translation.x *= -1.0 + case .bottom, .trailing: + break + } + var translationAmount: CGFloat + switch style { + case .top, .bottom: + translationAmount = translation.y >= 0 ? translation.y : -pow(abs(translation.y), 0.7) + case .leading, .trailing: + translationAmount = translation.x >= 0 ? translation.x : -pow(abs(translation.x), 0.7) } - var translationAmount = translation.y >= 0 ? translation.y : -pow(abs(translation.y), 0.7) if !closing { // Turn on rubber banding if background view is inset from message view. if let background = (messageView as? BackgroundViewable)?.backgroundView, background != view { @@ -214,6 +272,10 @@ public class TopBottomAnimation: NSObject, Animator { rubberBanding = background.frame.minY > 0 case .bottom: rubberBanding = background.frame.maxY < view.bounds.height + case .leading: + rubberBanding = background.frame.minX > 0 + case .trailing: + rubberBanding = background.frame.maxX < view.bounds.width } } if !rubberBanding && translationAmount < 0 { return } @@ -226,19 +288,30 @@ public class TopBottomAnimation: NSObject, Animator { view.transform = CGAffineTransform(translationX: 0, y: -translationAmount) case .bottom: view.transform = CGAffineTransform(translationX: 0, y: translationAmount) + case .leading: + view.transform = CGAffineTransform(translationX: -translationAmount, y: 0) + case .trailing: + view.transform = CGAffineTransform(translationX: translationAmount, y: 0) + } + switch style { + case .top, .bottom: + closeSpeed = velocity.y + closePercent = translation.y / length + panTranslation = translation.y + case .leading, .trailing: + closeSpeed = velocity.x + closePercent = translation.x / length + panTranslation = translation.x } - closeSpeed = velocity.y - closePercent = translation.y / height - panTranslationY = translation.y case .ended, .cancelled: - if closeSpeed > closeSpeedThreshold || closePercent > closePercentThreshold || panTranslationY > closeAbsoluteThreshold { + if closeSpeed > closeSpeedThreshold || closePercent > closePercentThreshold || panTranslation > closeAbsoluteThreshold { delegate?.hide(animator: self) } else { closing = false rubberBanding = false closeSpeed = 0.0 closePercent = 0.0 - panTranslationY = 0.0 + panTranslation = 0.0 showAnimation(completion: { (completed) in self.delegate?.panEnded(animator: self) }) diff --git a/SwiftMessages/UILayoutPriority+Extensions.swift b/SwiftMessages/UILayoutPriority+Extensions.swift index 1fd3ab88..ae6dc07e 100644 --- a/SwiftMessages/UILayoutPriority+Extensions.swift +++ b/SwiftMessages/UILayoutPriority+Extensions.swift @@ -9,10 +9,18 @@ import UIKit /// The priority used for `MessageSizeable` constraints -public extension UILayoutPriority { - static let aboveMessageSizeable: UILayoutPriority = messageInset + 1 - static let belowMessageSizeable: UILayoutPriority = messageSize - 1 - static let messageSize: UILayoutPriority = UILayoutPriority(900) - static let messageInset: UILayoutPriority = UILayoutPriority(901) +extension UILayoutPriority { + /// A constraint priority higher than those used for `MessageSizeable` + public static let aboveMessageSizeable: UILayoutPriority = messageInsetsBounds + 1 + + /// A constraint priority lower than those used for `MessageSizeable` + public static let belowMessageSizeable: UILayoutPriority = messageCenter - 1 + + static let messageCenter: UILayoutPriority = UILayoutPriority(900) + static let messageSize: UILayoutPriority = UILayoutPriority(901) + static let messageInsets: UILayoutPriority = UILayoutPriority(902) + static let messageCenterBounds: UILayoutPriority = UILayoutPriority(903) + static let messageSizeBounds: UILayoutPriority = UILayoutPriority(904) + static let messageInsetsBounds: UILayoutPriority = UILayoutPriority(905) } diff --git a/SwiftMessages/UIViewController+Extensions.swift b/SwiftMessages/UIViewController+Extensions.swift index 7fbd4dd1..6cedc0d5 100644 --- a/SwiftMessages/UIViewController+Extensions.swift +++ b/SwiftMessages/UIViewController+Extensions.swift @@ -87,14 +87,14 @@ extension UIViewController { } extension SwiftMessages.PresentationStyle { - /// A temporary workaround to allow custom presentation contexts using `TopBottomAnimation` + /// A temporary workaround to allow custom presentation contexts using `EdgeAnimation` /// to display properly behind bars. THe long term solution is to refactor all of the /// presentation context logic to work with safe area insets. - var topBottomStyle: TopBottomAnimation.Style? { + var topBottomStyle: EdgeAnimation.Style? { switch self { case .top: return .top case .bottom: return .bottom - case .custom(let animator): return (animator as? TopBottomAnimation)?.style + case .custom(let animator): return (animator as? EdgeAnimation)?.style case .center: return nil } } From e7d7e00c2d7f34bf0405c28e853564195bf369c3 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 20 Feb 2021 12:13:47 -0600 Subject: [PATCH 080/139] Adjust edge animation timing --- SwiftMessages.xcodeproj/project.pbxproj | 8 ++++---- ...{TopBottomAnimation.swift => EdgeAnimation.swift} | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) rename SwiftMessages/{TopBottomAnimation.swift => EdgeAnimation.swift} (97%) diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 47ac1180..23a9f5fe 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -55,7 +55,7 @@ 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */; }; 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; - 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; + 2298C2091EE486E300E2DDC1 /* EdgeAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* EdgeAnimation.swift */; }; 22DFC9161EFF30F6001B1CA1 /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */; }; 22DFC9181F00674E001B1CA1 /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */; }; 22E01F641E74EC8B00ACE19A /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22E01F631E74EC8B00ACE19A /* MaskingView.swift */; }; @@ -143,7 +143,7 @@ 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILayoutPriority+Extensions.swift"; sourceTree = ""; }; 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; - 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; + 2298C2081EE486E300E2DDC1 /* EdgeAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EdgeAnimation.swift; sourceTree = ""; }; 22A2EA6E24EC6CFA00BB2540 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CenteredView.xib; path = Resources/CenteredView.xib; sourceTree = ""; }; 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsPanHandler.swift; sourceTree = ""; }; @@ -221,7 +221,7 @@ 2244656C1EF1D62700C50413 /* Animations */ = { isa = PBXGroup; children = ( - 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */, + 2298C2081EE486E300E2DDC1 /* EdgeAnimation.swift */, 2270044A1FAFA6DD0045DDC3 /* PhysicsAnimation.swift */, 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */, ); @@ -556,7 +556,7 @@ 86BBA8FF1D5E040600FE8F16 /* Presenter.swift in Sources */, 86BBA9051D5E040C00FE8F16 /* Theme.swift in Sources */, 86BBA9081D5E040C00FE8F16 /* Error.swift in Sources */, - 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */, + 2298C2091EE486E300E2DDC1 /* EdgeAnimation.swift in Sources */, 86589D471D64B6E40041676C /* BaseView.swift in Sources */, 225304622290C76E00A03ACF /* NSLayoutConstraint+Extensions.swift in Sources */, 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */, diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/EdgeAnimation.swift similarity index 97% rename from SwiftMessages/TopBottomAnimation.swift rename to SwiftMessages/EdgeAnimation.swift index f8afc781..21039378 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/EdgeAnimation.swift @@ -1,5 +1,5 @@ // -// TopBottomAnimation.swift +// EdgeAnimation.swift // SwiftMessages // // Created by Timothy Moose on 6/4/17. @@ -24,9 +24,9 @@ public class EdgeAnimation: NSObject, Animator { public let style: Style - open var showDuration: TimeInterval = 0.4 + open var showDuration: TimeInterval = 0.35 - open var hideDuration: TimeInterval = 0.2 + open var hideDuration: TimeInterval = 0.25 open var springDamping: CGFloat = 0.8 @@ -65,7 +65,7 @@ public class EdgeAnimation: NSObject, Animator { NotificationCenter.default.removeObserver(self) let view = context.messageView self.context = context - UIView.animate(withDuration: hideDuration, delay: 0, options: [.beginFromCurrentState, .curveEaseIn], animations: { + UIView.animate(withDuration: hideDuration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: [.beginFromCurrentState]) { switch self.style { case .top: view.transform = CGAffineTransform(translationX: 0, y: -view.frame.height) @@ -76,14 +76,14 @@ public class EdgeAnimation: NSObject, Animator { case .trailing: view.transform = CGAffineTransform(translationX: view.frame.maxX + view.frame.width, y: 0) } - }, completion: { completed in + } completion: { completed in #if SWIFTMESSAGES_APP_EXTENSIONS completion(completed) #else // Fix #131 by always completing if application isn't active. completion(completed || UIApplication.shared.applicationState != .active) #endif - }) + } } func install(context: AnimationContext) { From 46347dad9944042bbdf0ba315ee977146d0ef932 Mon Sep 17 00:00:00 2001 From: Seyed Mojtaba Hosseini Zeidabadi Date: Mon, 22 Feb 2021 17:36:37 +0330 Subject: [PATCH 081/139] Fix all comments misspellings. (#456) * Fix all comments misspellings. * Fix spell of `additionalAccessibilityElements`. Co-authored-by: Seyed Mojtaba Hosseini Zeidabadi --- SwiftMessages/AccessibleMessage.swift | 2 +- SwiftMessages/Animator.swift | 10 +++++----- SwiftMessages/Identifiable.swift | 2 +- SwiftMessages/MessageView.swift | 8 ++++---- SwiftMessages/Presenter.swift | 4 ++-- SwiftMessages/SwiftMessages.swift | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/SwiftMessages/AccessibleMessage.swift b/SwiftMessages/AccessibleMessage.swift index 47a628ae..d540ecea 100644 --- a/SwiftMessages/AccessibleMessage.swift +++ b/SwiftMessages/AccessibleMessage.swift @@ -16,5 +16,5 @@ import Foundation public protocol AccessibleMessage { var accessibilityMessage: String? { get } var accessibilityElement: NSObject? { get } - var additonalAccessibilityElements: [NSObject]? { get } + var additionalAccessibilityElements: [NSObject]? { get } } diff --git a/SwiftMessages/Animator.swift b/SwiftMessages/Animator.swift index 292ea395..3897dd1f 100644 --- a/SwiftMessages/Animator.swift +++ b/SwiftMessages/Animator.swift @@ -18,7 +18,7 @@ public protocol AnimationDelegate: class { /** An option set representing the known types of safe area conflicts - that could require margin adustments on the message view in order to + that could require margin adjustments on the message view in order to get the layouts to look right. */ public struct SafeZoneConflicts: OptionSet { @@ -71,12 +71,12 @@ public protocol Animator: class { func hide(context: AnimationContext, completion: @escaping AnimationCompletion) - /// The show animation duration. If the animation duration is unknown, such as if using `UIDynamnicAnimator`, - /// then profide an estimate. This value is used by `SwiftMessagesSegue`. + /// The show animation duration. If the animation duration is unknown, such as if using `UIDynamicAnimator`, + /// then provide an estimate. This value is used by `SwiftMessagesSegue`. var showDuration: TimeInterval { get } - /// The hide animation duration. If the animation duration is unknown, such as if using `UIDynamnicAnimator`, - /// then profide an estimate. This value is used by `SwiftMessagesSegue`. + /// The hide animation duration. If the animation duration is unknown, such as if using `UIDynamicAnimator`, + /// then provide an estimate. This value is used by `SwiftMessagesSegue`. var hideDuration: TimeInterval { get } } diff --git a/SwiftMessages/Identifiable.swift b/SwiftMessages/Identifiable.swift index cd288492..4594b2d0 100644 --- a/SwiftMessages/Identifiable.swift +++ b/SwiftMessages/Identifiable.swift @@ -14,7 +14,7 @@ import Foundation representation of the content of the message view. For example, `MessageView`, combines the title and message body text. - This protocol is optional. Messave views that don't adopt `Identifiable` will not + This protocol is optional. Message views that don't adopt `Identifiable` will not have duplicates removed. */ public protocol Identifiable { diff --git a/SwiftMessages/MessageView.swift b/SwiftMessages/MessageView.swift index 7bc1b462..d9be31d9 100644 --- a/SwiftMessages/MessageView.swift +++ b/SwiftMessages/MessageView.swift @@ -88,7 +88,7 @@ open class MessageView: BaseView, Identifiable, AccessibleMessage { /** An optional prefix for the `accessibilityMessage` that can - be used to futher clarify the message for VoiceOver. For example, + be used to further clarify the message for VoiceOver. For example, the view's background color or icon might convey that a message is a warning, in which case one may specify the value "warning". */ @@ -108,7 +108,7 @@ open class MessageView: BaseView, Identifiable, AccessibleMessage { return backgroundView } - open var additonalAccessibilityElements: [NSObject]? { + open var additionalAccessibilityElements: [NSObject]? { var elements: [NSObject] = [] func getAccessibleSubviews(view: UIView) { for subview in view.subviews { @@ -206,7 +206,7 @@ extension MessageView { /* MARK: - Layout adjustments - This extention provides a few convenience functions for adjusting the layout. + This extension provides a few convenience functions for adjusting the layout. */ extension MessageView { @@ -236,7 +236,7 @@ extension MessageView { /* MARK: - Theming - This extention provides a few convenience functions for setting styles, + This extension provides a few convenience functions for setting styles, colors and icons. You are encouraged to write your own such functions if these don't exactly meet your needs. */ diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index 25fc11c7..c4e5549f 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -175,7 +175,7 @@ class Presenter: NSObject { private func showAccessibilityFocus() { guard let accessibleMessage = view as? AccessibleMessage, - let focus = accessibleMessage.accessibilityElement ?? accessibleMessage.additonalAccessibilityElements?.first else { return } + let focus = accessibleMessage.accessibilityElement ?? accessibleMessage.additionalAccessibilityElements?.first else { return } UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: focus) } @@ -388,7 +388,7 @@ class Presenter: NSObject { } elements.append(element) } - if let additional = accessibleMessage.additonalAccessibilityElements { + if let additional = accessibleMessage.additionalAccessibilityElements { elements += additional } } else { diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index d5e6ba93..dfae859c 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -55,8 +55,8 @@ open class SwiftMessages { appropriate one is found. Otherwise, it is displayed in a new window at level `UIWindow.Level.normal`. Use this option to automatically display under bars, where applicable. Because this option involves a top-down - search, an approrpiate context might not be found when the view controller - heirarchy incorporates custom containers. If this is the case, the + search, an appropriate context might not be found when the view controller + hierarchy incorporates custom containers. If this is the case, the .ViewController option can provide a more targeted context. */ case automatic @@ -87,7 +87,7 @@ open class SwiftMessages { appropriate one is found using the given view controller as a starting point and searching up the parent view controller chain. Otherwise, it is displayed in the given view controller's view. This option can be used - for targeted placement in a view controller heirarchy. + for targeted placement in a view controller hierarchy. */ case viewController(_: UIViewController) From cc1b635513ebd9f350b41a172ec418dc3593494f Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 22 Feb 2021 08:17:53 -0600 Subject: [PATCH 082/139] Add absoluteInsets size option --- SwiftMessages/Layout.swift | 11 +++++++++++ SwiftMessages/MaskingView.swift | 16 +++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift index 4afcf7b7..0d02fa6c 100644 --- a/SwiftMessages/Layout.swift +++ b/SwiftMessages/Layout.swift @@ -35,6 +35,7 @@ public struct Layout { public enum Dimension { case absolute(CGFloat) case relative(CGFloat, to: Boundary) + case absoluteInsets(CGFloat, to: Boundary) } public var width: Dimension? @@ -81,6 +82,16 @@ extension Layout.Insets.Dimension { } } +extension Layout.Size.Dimension { + var boundary: Layout.Boundary? { + switch self { + case .absolute(_): return nil + case .relative(_, let boundary): return boundary + case .absoluteInsets(_, let boundary): return boundary + } + } +} + extension Layout.Center.Dimension { var boundary: Layout.Boundary { switch self { diff --git a/SwiftMessages/MaskingView.swift b/SwiftMessages/MaskingView.swift index 81301994..08c31d20 100644 --- a/SwiftMessages/MaskingView.swift +++ b/SwiftMessages/MaskingView.swift @@ -417,10 +417,8 @@ class MaskingView: PassthroughView, LayoutInstalling { for dimension: Layout.Size.Dimension, extractor: (CGRect) -> CGFloat ) -> CGFloat { - switch dimension { - case .absolute(let dimension): - return dimension - case .relative(let percentage, let boundary): + let insetBounds: CGRect = { + guard let boundary = dimension.boundary else { return .zero } let insets: UIEdgeInsets switch boundary { case .superview: insets = .zero @@ -432,7 +430,15 @@ class MaskingView: PassthroughView, LayoutInstalling { insets = layoutMargins } } - return extractor(bounds.inset(by: insets)) * percentage + return bounds.inset(by: insets) + }() + switch dimension { + case .absolute(let dimension): + return dimension + case .relative(let percentage, _): + return extractor(insetBounds) * percentage + case .absoluteInsets(let dimension, _): + return extractor(insetBounds) - dimension * 2 } } From f3a0aca1111e891841e44227ec6a1d0d11b7de9d Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 22 Feb 2021 08:21:56 -0600 Subject: [PATCH 083/139] Fix arg name --- SwiftMessages/Layout.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift index 0d02fa6c..83100822 100644 --- a/SwiftMessages/Layout.swift +++ b/SwiftMessages/Layout.swift @@ -35,7 +35,7 @@ public struct Layout { public enum Dimension { case absolute(CGFloat) case relative(CGFloat, to: Boundary) - case absoluteInsets(CGFloat, to: Boundary) + case absoluteInsets(CGFloat, from: Boundary) } public var width: Dimension? From 4408c09c863b1c6af4d053fe17fd532a4f96b237 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 22 Feb 2021 08:33:49 -0600 Subject: [PATCH 084/139] Public Layout initializer --- SwiftMessages/Layout.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift index 83100822..09c2c16f 100644 --- a/SwiftMessages/Layout.swift +++ b/SwiftMessages/Layout.swift @@ -24,6 +24,8 @@ public struct Layout { public var min = Layout() public var max = Layout() + public init() {} + public enum Boundary { case superview case safeArea From 851e798a027bab1457eb1afae49c55705eaf7bec Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 11 Mar 2021 14:17:50 -0600 Subject: [PATCH 085/139] Stop using deprecated keyWindow API --- SwiftMessages.xcodeproj/project.pbxproj | 4 ++++ SwiftMessages/Presenter.swift | 2 +- .../SwiftMessages.Config+Extensions.swift | 2 +- SwiftMessages/UIWindow+Extensions.swift | 24 +++++++++++++++++++ SwiftMessages/WindowViewController.swift | 2 +- 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 SwiftMessages/UIWindow+Extensions.swift diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 4eef9ad5..b80cc86b 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -54,6 +54,7 @@ 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; + 229F778125FAB1E9008C2ACB /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */; }; 22DFC9161EFF30F6001B1CA1 /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */; }; 22DFC9181F00674E001B1CA1 /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */; }; 22E01F641E74EC8B00ACE19A /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22E01F631E74EC8B00ACE19A /* MaskingView.swift */; }; @@ -140,6 +141,7 @@ 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; + 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Extensions.swift"; sourceTree = ""; }; 22A2EA6E24EC6CFA00BB2540 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CenteredView.xib; path = Resources/CenteredView.xib; sourceTree = ""; }; 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsPanHandler.swift; sourceTree = ""; }; @@ -209,6 +211,7 @@ children = ( 220655111FAF82B600F4E00F /* MarginAdjustable+Extensions.swift */, 22774B9F20B5EF2A00813732 /* UIEdgeInsets+Extensions.swift */, + 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */, ); name = Extensions; sourceTree = ""; @@ -546,6 +549,7 @@ 86BBA9041D5E040600FE8F16 /* NSBundle+Extensions.swift in Sources */, 86BBA8FD1D5E03F800FE8F16 /* SwiftMessages.swift in Sources */, 86BBA9021D5E040600FE8F16 /* WindowViewController.swift in Sources */, + 229F778125FAB1E9008C2ACB /* UIWindow+Extensions.swift in Sources */, 86BBA8FF1D5E040600FE8F16 /* Presenter.swift in Sources */, 86BBA9051D5E040C00FE8F16 /* Theme.swift in Sources */, 86BBA9081D5E040C00FE8F16 /* Error.swift in Sources */, diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index e16c076e..43b19ee7 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -301,7 +301,7 @@ class Presenter: NSObject { #if SWIFTMESSAGES_APP_EXTENSIONS throw SwiftMessagesError.noRootViewController #else - if let rootViewController = UIApplication.shared.keyWindow?.rootViewController { + if let rootViewController = UIWindow.keyWindow?.rootViewController { let viewController = rootViewController.sm_selectPresentationContextTopDown(config) return .viewController(Weak(value: viewController)) } else { diff --git a/SwiftMessages/SwiftMessages.Config+Extensions.swift b/SwiftMessages/SwiftMessages.Config+Extensions.swift index 2dfe7ae4..9682b5b9 100644 --- a/SwiftMessages/SwiftMessages.Config+Extensions.swift +++ b/SwiftMessages/SwiftMessages.Config+Extensions.swift @@ -25,7 +25,7 @@ extension SwiftMessages.Config { #if SWIFTMESSAGES_APP_EXTENSIONS return nil #else - return UIApplication.shared.keyWindow?.windowScene + return UIWindow.keyWindow?.windowScene #endif } } diff --git a/SwiftMessages/UIWindow+Extensions.swift b/SwiftMessages/UIWindow+Extensions.swift new file mode 100644 index 00000000..ff5239a8 --- /dev/null +++ b/SwiftMessages/UIWindow+Extensions.swift @@ -0,0 +1,24 @@ +// +// UIWindow+Extensions.swift +// SwiftMessages +// +// Created by Timothy Moose on 3/11/21. +// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. +// + +import UIKit + +extension UIWindow { + static var keyWindow: UIWindow? { + if #available(iOS 13.0, *) { + return UIApplication.shared.connectedScenes + .filter { $0.activationState == .foregroundActive } + .compactMap { $0 as? UIWindowScene } + .first?.windows + .filter { $0.isKeyWindow } + .first + } else { + return UIApplication.shared.keyWindow + } + } +} diff --git a/SwiftMessages/WindowViewController.swift b/SwiftMessages/WindowViewController.swift index 65b85854..5e61af1d 100644 --- a/SwiftMessages/WindowViewController.swift +++ b/SwiftMessages/WindowViewController.swift @@ -37,7 +37,7 @@ open class WindowViewController: UIViewController window?.windowScene = config.windowScene if config.shouldBecomeKeyWindow { #if !SWIFTMESSAGES_APP_EXTENSIONS - previousKeyWindow = UIApplication.shared.keyWindow + previousKeyWindow = UIWindow.keyWindow #endif } show( From eeb685398f4cea6f8c54e63bd87a0d81393cc515 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 11 Mar 2021 14:34:30 -0600 Subject: [PATCH 086/139] Improve key window restoration logic --- SwiftMessages/WindowViewController.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SwiftMessages/WindowViewController.swift b/SwiftMessages/WindowViewController.swift index 5e61af1d..96b30095 100644 --- a/SwiftMessages/WindowViewController.swift +++ b/SwiftMessages/WindowViewController.swift @@ -35,11 +35,9 @@ open class WindowViewController: UIViewController func install() { if #available(iOS 13, *) { window?.windowScene = config.windowScene - if config.shouldBecomeKeyWindow { - #if !SWIFTMESSAGES_APP_EXTENSIONS - previousKeyWindow = UIWindow.keyWindow - #endif - } + #if !SWIFTMESSAGES_APP_EXTENSIONS + previousKeyWindow = UIWindow.keyWindow + #endif show( becomeKey: config.shouldBecomeKeyWindow, frame: config.windowScene?.coordinateSpace.bounds @@ -60,12 +58,14 @@ open class WindowViewController: UIViewController } func uninstall() { + if window?.isKeyWindow == true { + previousKeyWindow?.makeKeyAndVisible() + } if #available(iOS 13, *) { window?.windowScene = nil } window?.isHidden = true window = nil - previousKeyWindow?.makeKeyAndVisible() } required public init?(coder aDecoder: NSCoder) { From 76d7971c95f4f8461b36ca82b801f775994b9a1d Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 18 Mar 2021 11:20:17 -0500 Subject: [PATCH 087/139] Update podspec --- CHANGELOG.md | 6 ++++++ SwiftMessages.podspec | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 239b08f7..8beecbfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.1 + +### Fixes + +* #455 #458 Restore key window after message is interacted with. When a message becomes the key window, such as if the user interacts with the message, iOS does not automatically restore the previous key window when the message is dismissed. SwiftMessages has some logic in `WindowViewController` to restore the key window. This change makes that logic more robust. + ## 9.0.0 ### Features diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 22b2d781..f9fafd91 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.0' + spec.version = '9.0.1' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } From c63e64e8a8988f0885e3ee23fb1e50f9b6cbd584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20=C3=87ift=C3=A7i?= Date: Sun, 21 Mar 2021 20:51:39 +0300 Subject: [PATCH 088/139] refactor(MessageView): remove redundant words for `button` (#461) --- SwiftMessages/MessageView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages/MessageView.swift b/SwiftMessages/MessageView.swift index d9be31d9..e844b074 100644 --- a/SwiftMessages/MessageView.swift +++ b/SwiftMessages/MessageView.swift @@ -55,7 +55,7 @@ open class MessageView: BaseView, Identifiable, AccessibleMessage { /// An optional button. This buttons' `.TouchUpInside` event will automatically /// invoke the optional `buttonTapHandler`, but its fine to add other target - /// action handlers can be added. + /// action handlers. @IBOutlet open var button: UIButton? { didSet { if let old = oldValue { From ba6c3e7284a531965feff058ba36784f30017843 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Wed, 24 Mar 2021 10:52:15 -0500 Subject: [PATCH 089/139] Fix app extension compile error when using CocoaPods --- CHANGELOG.md | 6 + SwiftMessages.podspec | 2 +- SwiftMessages/UIWindow+Extensions.swift | 2 + iMessageDemo/Podfile | 19 + iMessageDemo/Podfile.lock | 16 + .../Local Podspecs/SwiftMessages.podspec.json | 49 + iMessageDemo/Pods/Manifest.lock | 16 + .../Pods/Pods.xcodeproj/project.pbxproj | 1188 +++++++++++++++++ .../Pods-iMessageDemo-Info.plist | 26 + ...ods-iMessageDemo-acknowledgements.markdown | 14 + .../Pods-iMessageDemo-acknowledgements.plist | 46 + .../Pods-iMessageDemo-dummy.m | 5 + ...mo-frameworks-Debug-input-files.xcfilelist | 2 + ...o-frameworks-Debug-output-files.xcfilelist | 1 + ...-frameworks-Release-input-files.xcfilelist | 2 + ...frameworks-Release-output-files.xcfilelist | 1 + .../Pods-iMessageDemo-frameworks.sh | 185 +++ .../Pods-iMessageDemo-umbrella.h | 16 + .../Pods-iMessageDemo.debug.xcconfig | 14 + .../Pods-iMessageDemo.modulemap | 6 + .../Pods-iMessageDemo.release.xcconfig | 14 + .../Pods-iMessageExtensionDemo-Info.plist | 26 + ...ageExtensionDemo-acknowledgements.markdown | 14 + ...essageExtensionDemo-acknowledgements.plist | 46 + .../Pods-iMessageExtensionDemo-dummy.m | 5 + .../Pods-iMessageExtensionDemo-umbrella.h | 16 + .../Pods-iMessageExtensionDemo.debug.xcconfig | 13 + .../Pods-iMessageExtensionDemo.modulemap | 6 + ...ods-iMessageExtensionDemo.release.xcconfig | 13 + ...dle-SwiftMessages-SwiftMessages-Info.plist | 24 + ...ges_SwiftMessages-SwiftMessages-Info.plist | 24 + .../SwiftMessages/SwiftMessages-Info.plist | 26 + .../SwiftMessages/SwiftMessages-dummy.m | 5 + .../SwiftMessages/SwiftMessages-prefix.pch | 12 + .../SwiftMessages/SwiftMessages-umbrella.h | 16 + .../SwiftMessages.debug.xcconfig | 15 + .../SwiftMessages/SwiftMessages.modulemap | 6 + .../SwiftMessages.release.xcconfig | 15 + .../iMessageDemo.xcodeproj/project.pbxproj | 166 +-- .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + 41 files changed, 2020 insertions(+), 76 deletions(-) create mode 100644 iMessageDemo/Podfile create mode 100644 iMessageDemo/Podfile.lock create mode 100644 iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json create mode 100644 iMessageDemo/Pods/Manifest.lock create mode 100644 iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-Info.plist create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.markdown create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.plist create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-dummy.m create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-input-files.xcfilelist create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-output-files.xcfilelist create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-input-files.xcfilelist create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-output-files.xcfilelist create mode 100755 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks.sh create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-umbrella.h create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.debug.xcconfig create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.modulemap create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.release.xcconfig create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-Info.plist create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.markdown create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.plist create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-dummy.m create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-umbrella.h create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.debug.xcconfig create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.modulemap create mode 100644 iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.release.xcconfig create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages-SwiftMessages-Info.plist create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-dummy.m create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-prefix.pch create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-umbrella.h create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.debug.xcconfig create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.modulemap create mode 100644 iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.release.xcconfig create mode 100644 iMessageDemo/iMessageDemo.xcworkspace/contents.xcworkspacedata create mode 100644 iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/CHANGELOG.md b/CHANGELOG.md index 8beecbfb..08f50bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.2 + +### Fixes + +* Fix app extension compile error when using CocoaPods. + ## 9.0.1 ### Fixes diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index f9fafd91..820b4e9a 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.1' + spec.version = '9.0.2' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } diff --git a/SwiftMessages/UIWindow+Extensions.swift b/SwiftMessages/UIWindow+Extensions.swift index ff5239a8..d98c6caf 100644 --- a/SwiftMessages/UIWindow+Extensions.swift +++ b/SwiftMessages/UIWindow+Extensions.swift @@ -9,6 +9,7 @@ import UIKit extension UIWindow { + #if !SWIFTMESSAGES_APP_EXTENSIONS static var keyWindow: UIWindow? { if #available(iOS 13.0, *) { return UIApplication.shared.connectedScenes @@ -21,4 +22,5 @@ extension UIWindow { return UIApplication.shared.keyWindow } } + #endif } diff --git a/iMessageDemo/Podfile b/iMessageDemo/Podfile new file mode 100644 index 00000000..7c45a63f --- /dev/null +++ b/iMessageDemo/Podfile @@ -0,0 +1,19 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' + +target 'iMessageDemo' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for iMessageDemo + +end + +target 'iMessageExtensionDemo' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for iMessageExtensionDemo + pod 'SwiftMessages/AppExtension', :path => "../" + +end diff --git a/iMessageDemo/Podfile.lock b/iMessageDemo/Podfile.lock new file mode 100644 index 00000000..552070e5 --- /dev/null +++ b/iMessageDemo/Podfile.lock @@ -0,0 +1,16 @@ +PODS: + - SwiftMessages/AppExtension (9.0.1) + +DEPENDENCIES: + - SwiftMessages/AppExtension (from `../`) + +EXTERNAL SOURCES: + SwiftMessages: + :path: "../" + +SPEC CHECKSUMS: + SwiftMessages: b71f53eb919887c0273bf43cbc002bd4f0cfb3d6 + +PODFILE CHECKSUM: 4cfafdad7d8903d0f4cfadbe05660bcdeff7c9e6 + +COCOAPODS: 1.10.0 diff --git a/iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json b/iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json new file mode 100644 index 00000000..72a5b097 --- /dev/null +++ b/iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json @@ -0,0 +1,49 @@ +{ + "name": "SwiftMessages", + "version": "9.0.1", + "license": { + "type": "MIT" + }, + "homepage": "https://github.com/SwiftKickMobile/SwiftMessages", + "authors": { + "Timothy Moose": "tim@swiftkick.it" + }, + "summary": "A very flexible message bar for iOS written in Swift.", + "source": { + "git": "https://github.com/SwiftKickMobile/SwiftMessages.git", + "tag": "9.0.1" + }, + "platforms": { + "ios": "9.0" + }, + "swift_versions": "5.0", + "frameworks": "UIKit", + "requires_arc": true, + "default_subspecs": "App", + "subspecs": [ + { + "name": "App", + "source_files": "SwiftMessages/**/*.swift", + "resource_bundles": { + "SwiftMessages": [ + "SwiftMessages/Resources/*.*" + ] + } + }, + { + "name": "AppExtension", + "source_files": "SwiftMessages/**/*.swift", + "exclude_files": "SwiftMessages/**/SegueConvenienceClasses.swift", + "resource_bundles": { + "SwiftMessages_SwiftMessages": [ + "SwiftMessages/Resources/**/*.*" + ] + }, + "pod_target_xcconfig": { + "SWIFT_ACTIVE_COMPILATION_CONDITIONS": "SWIFTMESSAGES_APP_EXTENSIONS", + "GCC_PREPROCESSOR_DEFINITIONS": "SWIFTMESSAGES_APP_EXTENSIONS=1" + } + } + ], + "swift_version": "5.0" +} diff --git a/iMessageDemo/Pods/Manifest.lock b/iMessageDemo/Pods/Manifest.lock new file mode 100644 index 00000000..552070e5 --- /dev/null +++ b/iMessageDemo/Pods/Manifest.lock @@ -0,0 +1,16 @@ +PODS: + - SwiftMessages/AppExtension (9.0.1) + +DEPENDENCIES: + - SwiftMessages/AppExtension (from `../`) + +EXTERNAL SOURCES: + SwiftMessages: + :path: "../" + +SPEC CHECKSUMS: + SwiftMessages: b71f53eb919887c0273bf43cbc002bd4f0cfb3d6 + +PODFILE CHECKSUM: 4cfafdad7d8903d0f4cfadbe05660bcdeff7c9e6 + +COCOAPODS: 1.10.0 diff --git a/iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj b/iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 00000000..468092a5 --- /dev/null +++ b/iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,1188 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 00468531530F8A70E3D83622BD482026 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E6941E59EF0D89949E3DF3D89488430 /* Weak.swift */; }; + 0303F738260F2C9BAE20B79DE84E82BC /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2337E6D5F621F3CE9A1E3761984EBE87 /* PhysicsPanHandler.swift */; }; + 0B42A04122166EAD384BCE37FD450FAF /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8901520225CE89F44E6DE88688F29C10 /* MessageView.swift */; }; + 0CE00BF7FB0F6376D89B0AFF1CFD7510 /* PassthroughView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C557E1DC95AFA417E94ED01301F9F2 /* PassthroughView.swift */; }; + 0E7AE1B3CE2734B39ACCE812B4320B44 /* MarginAdjustable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B91AD9D9E743D17D553D48103BE27C46 /* MarginAdjustable+Extensions.swift */; }; + 138A7742F76993FB9EE3555FD2808562 /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = A80433B71162112A79043CB64261DB51 /* successIconLight.png */; }; + 16047C447B00FAA7F42764EC4167C33B /* NSLayoutConstraint+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0970322A5DD8B4A8373C35ED051DE156 /* NSLayoutConstraint+Extensions.swift */; }; + 1F4159921A25C7B2A0E9C587387D829C /* errorIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B04615682E8B787C964824435BC6616 /* errorIconLight@2x.png */; }; + 1F6162906845BE72A5BCDAF14D6E14B9 /* warningIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 4512DEEA328AB0AAA95D77C84C89E02C /* warningIconSubtle.png */; }; + 2181E713FC7C00EE871FDA6CB62C7E8C /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5607E285A85AC7163B0B8FD447FD27E /* Theme.swift */; }; + 2558CABB502ED605BC21DCFC55A9C0B7 /* MessageView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AE62AA801971C530345349D18AFCCB82 /* MessageView.xib */; }; + 2B23A9DFDAACFE9C0AD5EB6899E63475 /* infoIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4FE466AC4123CDAE9FDA9FCF4FB9CC60 /* infoIconSubtle@2x.png */; }; + 33785D52B8888C2EA02BD0495408E352 /* successIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 72A865FFBAE49EF66A35CB9D709E8D7E /* successIconLight@3x.png */; }; + 3505AB28DBFA49FBE5C8250F3E067E60 /* KeyboardTrackingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536660614870EA0E051BF6BDDF495798 /* KeyboardTrackingView.swift */; }; + 365594AAFDD4EE947EB33E6E86A8578E /* errorIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = A850F76D7E3FEDC20FFB877454069171 /* errorIconSubtle.png */; }; + 425F2D4CE95436680D77C263FF15221B /* SwiftMessages_SwiftMessages.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BEBF018059B0DFCAC8494ABD1C578AD9 /* SwiftMessages_SwiftMessages.bundle */; }; + 4267FACE20717FF3F51C2ACAB8C395A4 /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D0E8B0020635F606875DD02735C502 /* BaseView.swift */; }; + 44150A4B5B2D251FCBB6CA07DC9872B5 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 267E35F9851AAE50DFB8FA0DCA7F2980 /* Animator.swift */; }; + 447E8A096C1ABD2E0AC9674E65A827E3 /* warningIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 0259757860B26C6072E2640B84EC6D45 /* warningIcon.png */; }; + 44C0F194D748EE88027414A5B2094E9B /* successIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C8155ED78358FA5CF39089176FBDE501 /* successIcon@3x.png */; }; + 461760E2818D72B948B60B4835E7B1ED /* NSBundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCF161BD9F1C2CAAFBCADE5E59BD3FD /* NSBundle+Extensions.swift */; }; + 462CDC24C5C8DD6905C4112B6B4BD2ED /* successIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = FC73E6C784AF6CA1F956F57F82ED2803 /* successIcon.png */; }; + 46CCA4DDFDBBDD2A9426BB96C08E4255 /* Pods-iMessageExtensionDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F40CA14AD738DD186B4DA8FD14AE5BD /* Pods-iMessageExtensionDemo-dummy.m */; }; + 492F085489FCAB0EEBE74B098F7D3F4D /* StatusLine.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7A6801849037A728E9BC50E06CE8AD2F /* StatusLine.xib */; }; + 4C78ED4E1780F5609E25CE03429C1DE4 /* errorIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 848251807107C20960A3DABAB27F7475 /* errorIconLight@3x.png */; }; + 4DB5D1FB08693DDDC32BCF19CC1B1AA0 /* warningIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 874D31DE863C88B1D699E1EBFBE0641B /* warningIconLight@2x.png */; }; + 4E703B2A80C64CF1142872BE31263940 /* errorIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 0892E032AE12339D1AD84BDCC78A3C07 /* errorIconLight.png */; }; + 4E9CCFC43646B6CDBE3B787AB09A0147 /* CardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 42F1E753E61B6EDED3908AC66994649C /* CardView.xib */; }; + 5260BD3289BAC54A20457099C4A57EFF /* errorIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 9D1FEAC04417D847EDC10783E054988F /* errorIcon.png */; }; + 52F4ED7F78829270B2AFE5EDBA9EEE2F /* UIEdgeInsets+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A13E69643D651322647C28E3F9E9C9 /* UIEdgeInsets+Extensions.swift */; }; + 560A2B1056FEFE42AC6524A2A1742CA2 /* Pods-iMessageExtensionDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAB201AD00CAB811B045E2FFB5C03A8 /* Pods-iMessageExtensionDemo-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 57072960EA4F0D307171ED90697D3FAF /* TabView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B7FD0618783A3E6B90D3A3323633959F /* TabView.xib */; }; + 5720D965B3CE67653082137053FBEC9C /* infoIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C110C924ED12D2D32ECC27503018A31 /* infoIconLight.png */; }; + 5750C24C3A9CAE11C7E36B37434912D0 /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CF61FDEFE095F0486E9914F2262ADB9 /* MaskingView.swift */; }; + 5DF3F4808ED4A6932839C11A5D742B93 /* successIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 54B278C80D821C120FA70ABB6CAF1F46 /* successIconSubtle@3x.png */; }; + 6320AE79D41E8D1F52AF66A670542561 /* CornerRoundingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F8D7902822221456B697BB41111E450 /* CornerRoundingView.swift */; }; + 64595C731B826EB19E9757D524E0BF76 /* warningIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CFBBC25592C97C925B6F81B53BE57CB /* warningIcon@3x.png */; }; + 683A7897D1E9A73F4717198B1C054D29 /* errorIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 60268FE48AA4DC9FD5060B1E5CE68453 /* errorIcon@2x.png */; }; + 6A539682FDDA0E5DA23E1B5F2BA133C1 /* errorIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6DEAADC09FEB1A8D5B90108103EE478 /* errorIcon@3x.png */; }; + 6C7DAA6A68AFDACD67F2C127CEF4DD6F /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C8F928170138667B9326F9655D75D /* UIWindow+Extensions.swift */; }; + 755DA479621A9D2BB8B84540DE648A7A /* warningIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 667DECE93ABCC6869A071FFEB0F83EA5 /* warningIconSubtle@3x.png */; }; + 7ACCA07CCFD868899D61F4B4AE5774DB /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2B7213B7DC5432DA2B272F25E17AA364 /* infoIconSubtle@3x.png */; }; + 7BC52E6F0D9D19B05E62E623E53FCE82 /* Pods-iMessageDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D0ECE831FB5E0EE1D68E837671320C7 /* Pods-iMessageDemo-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7E5ADF1F3B6849D5A0DF8E2B9C1861C5 /* PhysicsAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE3BED1799B2F867F5C984C2A051E36A /* PhysicsAnimation.swift */; }; + 8148CD8F2B38FB38B7B9CCC12E93ECFB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */; }; + 89ACEF0F9E524BD21D6C2460FEC375F8 /* warningIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = ED86D7B42F55040DCE162653FB3C7EDB /* warningIconSubtle@2x.png */; }; + 966B9C1EE6B73E430F03D51A4FD26D20 /* MarginAdjustable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C56947CAF8EFCC7858E1E2F1273427 /* MarginAdjustable.swift */; }; + 9CEE0E569456D932AA34329D2038DF98 /* SwiftMessagesSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFFDB7DDC6B6B064B9D12281E2531BFA /* SwiftMessagesSegue.swift */; }; + 9E3D4CA932041E99B6FD56D4E79A726F /* SwiftMessages-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C614EECDDFE644AF0BF7CB16A3D74404 /* SwiftMessages-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9FFE65CB6E825ECAE4838D53E7BA4C06 /* infoIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4412F313361EFEE7A0193533A5AC5999 /* infoIconLight@3x.png */; }; + A11E7A379B288CCA3AE6785B83FA4316 /* AccessibleMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDDAF8A2C45FDDDFD5AFA59203137551 /* AccessibleMessage.swift */; }; + A1734DB0A8A558B2397AF54E63F64416 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8341EF04E2B20C2BF6D4AF2240F80A56 /* Error.swift */; }; + A9EB0C8E49AB748B05CF7941ACAF8475 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */; }; + AC4F13F50EB63B484292D67692BC1F9D /* successIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 1DC54BB09EFDFEDE11F484FE73BEDC60 /* successIconSubtle.png */; }; + B2862C6DDAA6543BB2C8F4541F044564 /* SwiftMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3216CF40D770C387D45C3B4AF2CC9E0 /* SwiftMessages.swift */; }; + B2CC8FF0F9FF3FE929180CDB32B69F18 /* infoIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F7004673F1B51EEC365B32F0E060E564 /* infoIcon@2x.png */; }; + B42A7A38C8014DBDE2632B909F71C355 /* successIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 62755A788F910CA88887B6F63BBC545F /* successIcon@2x.png */; }; + B60094A8D1343B7351F0EF9C51F2F0DB /* infoIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 337B3108412E3812254B85BCC4F90EB8 /* infoIcon@3x.png */; }; + BB16D1E73A5D6B27DC4212926986107F /* warningIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BFEF746702215C33B51BEE64C4E48F0A /* warningIcon@2x.png */; }; + BBFE3BAFFCE67F4EACE0C67A7B7FFC3A /* successIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0B3A169D83BDA3613A661845D1607FC0 /* successIconSubtle@2x.png */; }; + BC4618CE535404A9540D4D110B5767A1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 396FCF260E9C2B3F11080A91E3D72334 /* TopBottomAnimation.swift */; }; + BDCF9C5E4F88B2B0AB6D4595E5A281E1 /* successIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F898B2AC5C3404C266BBCA3B6D22B5E4 /* successIconLight@2x.png */; }; + C384FB76A48C06F7581D0F7850F2F4F1 /* Pods-iMessageDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 14BF989232A1D55A0FDAAB70B5A8E1BF /* Pods-iMessageDemo-dummy.m */; }; + C3CDAED707B153A58674CB1AC4A33FB2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */; }; + C4598A458697C49C961BFDCD090B3A8F /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 06F2F626BE8417F1806CC5B17F210C90 /* infoIconSubtle.png */; }; + C5FFE932D5EBE2CC8F2ABFEA893D8E9C /* infoIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70E7AB099F856140EF93D5B94A967418 /* infoIcon.png */; }; + C6E73F201545CF5ED055C69CD4DB2EFF /* warningIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C17CFEF9B761A322945F74D86CA88036 /* warningIconLight@3x.png */; }; + C8F46E0A5853739D3F632B4828FDE9CC /* PassthroughWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382E6375390EBB09F829519F8ACCB7D7 /* PassthroughWindow.swift */; }; + CCF5CC8F6022DFD410DDCC99A90D58B0 /* warningIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 79E38069364BC5DF4EA88F352E28B242 /* warningIconLight.png */; }; + D49E06426C51C49E9058371138972A69 /* CALayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B5EF40CEC1F6DB23F428DC159D4BC2 /* CALayer+Extensions.swift */; }; + D61D59BCDFD2C3C7993CFE883DE60692 /* infoIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6516EE9BFCB9C53C151359F9D0247562 /* infoIconLight@2x.png */; }; + D8BDC20F1566606BF64001B6E96B14B6 /* errorIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 453BC098B6A052020C40DE576F684C7B /* errorIconSubtle@3x.png */; }; + D9077478C2FCD7C3DD1EBE9373281728 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C4C88778A19C193D1EC77FA77BAE4C /* UIViewController+Extensions.swift */; }; + E88597F65A00A5AF50EEF2ABA2392B2F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D245E0514AAC1A2B9A6D5EA2F383E90F /* UIKit.framework */; }; + E94E8711BDDA31B178AA032D3346C307 /* BackgroundViewable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAB58A9F688DD39112E6CDF20C8969C0 /* BackgroundViewable.swift */; }; + EDA146BF3FF59593677F8B2AA785D8A5 /* errorIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3C313FB1D33EF4B477FD5D3D6179A8BE /* errorIconSubtle@2x.png */; }; + F27E3EEAFDDAA6CB4E7407D6A46DAA5D /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3DF091E68C4659506DB08B0876BD274C /* CenteredView.xib */; }; + F50FE2EE47422AD39AC8F7F115081E7E /* SwiftMessages.Config+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C32E945AE3E6394EF85CD6BEC714B4 /* SwiftMessages.Config+Extensions.swift */; }; + F5642C087197B9033252FF10FBA92B59 /* WindowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8566413BFA3FE6827E63E30515C9B3 /* WindowViewController.swift */; }; + FA6CA270F521DF68A75E527954A2DDAD /* SwiftMessages-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A2F9031B7FA82A17F04D4403091DF836 /* SwiftMessages-dummy.m */; }; + FCB6832EB4D32EF085E770E8B4A9BC2C /* Identifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0DE01AB7D0935933E7AFBDF2945814 /* Identifiable.swift */; }; + FF01BC94FADD5A72282AEE043DF523A7 /* Presenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A965DD26246DCA8CE39FBAB348ABA24 /* Presenter.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 141E78A8858DBF8B2695DFEDCBDF5158 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1FC5E8328653C350899229BDF89FACE5; + remoteInfo = "SwiftMessages-SwiftMessages_SwiftMessages"; + }; + 4DB1DDB02425E67ED85C70C3B138E205 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DAB613A18652334F6BFC5F27BADF515D; + remoteInfo = SwiftMessages; + }; + 900F05D1477FFAB64FF410CBB6B9B74D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DAB613A18652334F6BFC5F27BADF515D; + remoteInfo = SwiftMessages; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0259757860B26C6072E2640B84EC6D45 /* warningIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIcon.png; path = SwiftMessages/Resources/warningIcon.png; sourceTree = ""; }; + 06F2F626BE8417F1806CC5B17F210C90 /* infoIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIconSubtle.png; path = SwiftMessages/Resources/infoIconSubtle.png; sourceTree = ""; }; + 0892E032AE12339D1AD84BDCC78A3C07 /* errorIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIconLight.png; path = SwiftMessages/Resources/errorIconLight.png; sourceTree = ""; }; + 093D5BBE2A96A1A7AC0432A3AB933576 /* Pods-iMessageDemo-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageDemo-Info.plist"; sourceTree = ""; }; + 0970322A5DD8B4A8373C35ED051DE156 /* NSLayoutConstraint+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSLayoutConstraint+Extensions.swift"; path = "SwiftMessages/NSLayoutConstraint+Extensions.swift"; sourceTree = ""; }; + 0A8566413BFA3FE6827E63E30515C9B3 /* WindowViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WindowViewController.swift; path = SwiftMessages/WindowViewController.swift; sourceTree = ""; }; + 0B3A169D83BDA3613A661845D1607FC0 /* successIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconSubtle@2x.png"; path = "SwiftMessages/Resources/successIconSubtle@2x.png"; sourceTree = ""; }; + 1341BB7116EC50FDF7062C6A91DEDF49 /* Pods-iMessageExtensionDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageExtensionDemo-acknowledgements.plist"; sourceTree = ""; }; + 14BF989232A1D55A0FDAAB70B5A8E1BF /* Pods-iMessageDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-iMessageDemo-dummy.m"; sourceTree = ""; }; + 15C4C88778A19C193D1EC77FA77BAE4C /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIViewController+Extensions.swift"; path = "SwiftMessages/UIViewController+Extensions.swift"; sourceTree = ""; }; + 19B5EF40CEC1F6DB23F428DC159D4BC2 /* CALayer+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CALayer+Extensions.swift"; path = "SwiftMessages/CALayer+Extensions.swift"; sourceTree = ""; }; + 1B04615682E8B787C964824435BC6616 /* errorIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconLight@2x.png"; path = "SwiftMessages/Resources/errorIconLight@2x.png"; sourceTree = ""; }; + 1DC54BB09EFDFEDE11F484FE73BEDC60 /* successIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIconSubtle.png; path = SwiftMessages/Resources/successIconSubtle.png; sourceTree = ""; }; + 2337E6D5F621F3CE9A1E3761984EBE87 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PhysicsPanHandler.swift; path = SwiftMessages/PhysicsPanHandler.swift; sourceTree = ""; }; + 267E35F9851AAE50DFB8FA0DCA7F2980 /* Animator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Animator.swift; path = SwiftMessages/Animator.swift; sourceTree = ""; }; + 2B6B36CBE6DC07B2F005E30EA2B121CB /* LICENSE.md */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE.md; sourceTree = ""; }; + 2B7213B7DC5432DA2B272F25E17AA364 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "SwiftMessages/Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; + 2CFBBC25592C97C925B6F81B53BE57CB /* warningIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIcon@3x.png"; path = "SwiftMessages/Resources/warningIcon@3x.png"; sourceTree = ""; }; + 2D0ECE831FB5E0EE1D68E837671320C7 /* Pods-iMessageDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-iMessageDemo-umbrella.h"; sourceTree = ""; }; + 2E6941E59EF0D89949E3DF3D89488430 /* Weak.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SwiftMessages/Weak.swift; sourceTree = ""; }; + 337B3108412E3812254B85BCC4F90EB8 /* infoIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIcon@3x.png"; path = "SwiftMessages/Resources/infoIcon@3x.png"; sourceTree = ""; }; + 346718C2C7A108C86535F89FEB0EC176 /* SwiftMessages.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SwiftMessages.modulemap; sourceTree = ""; }; + 382E6375390EBB09F829519F8ACCB7D7 /* PassthroughWindow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PassthroughWindow.swift; path = SwiftMessages/PassthroughWindow.swift; sourceTree = ""; }; + 396FCF260E9C2B3F11080A91E3D72334 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TopBottomAnimation.swift; path = SwiftMessages/TopBottomAnimation.swift; sourceTree = ""; }; + 397C8F928170138667B9326F9655D75D /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIWindow+Extensions.swift"; path = "SwiftMessages/UIWindow+Extensions.swift"; sourceTree = ""; }; + 3C313FB1D33EF4B477FD5D3D6179A8BE /* errorIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconSubtle@2x.png"; path = "SwiftMessages/Resources/errorIconSubtle@2x.png"; sourceTree = ""; }; + 3DF091E68C4659506DB08B0876BD274C /* CenteredView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = CenteredView.xib; path = SwiftMessages/Resources/CenteredView.xib; sourceTree = ""; }; + 42F1E753E61B6EDED3908AC66994649C /* CardView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = CardView.xib; path = SwiftMessages/Resources/CardView.xib; sourceTree = ""; }; + 4412F313361EFEE7A0193533A5AC5999 /* infoIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconLight@3x.png"; path = "SwiftMessages/Resources/infoIconLight@3x.png"; sourceTree = ""; }; + 4512DEEA328AB0AAA95D77C84C89E02C /* warningIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIconSubtle.png; path = SwiftMessages/Resources/warningIconSubtle.png; sourceTree = ""; }; + 453BC098B6A052020C40DE576F684C7B /* errorIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconSubtle@3x.png"; path = "SwiftMessages/Resources/errorIconSubtle@3x.png"; sourceTree = ""; }; + 4824F23D80FF9070A5F8A452DB11EB9A /* SwiftMessages.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SwiftMessages.framework; path = SwiftMessages.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4F8D7902822221456B697BB41111E450 /* CornerRoundingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CornerRoundingView.swift; path = SwiftMessages/CornerRoundingView.swift; sourceTree = ""; }; + 4FE466AC4123CDAE9FDA9FCF4FB9CC60 /* infoIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconSubtle@2x.png"; path = "SwiftMessages/Resources/infoIconSubtle@2x.png"; sourceTree = ""; }; + 536660614870EA0E051BF6BDDF495798 /* KeyboardTrackingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyboardTrackingView.swift; path = SwiftMessages/KeyboardTrackingView.swift; sourceTree = ""; }; + 54B278C80D821C120FA70ABB6CAF1F46 /* successIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconSubtle@3x.png"; path = "SwiftMessages/Resources/successIconSubtle@3x.png"; sourceTree = ""; }; + 5C0DE01AB7D0935933E7AFBDF2945814 /* Identifiable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Identifiable.swift; path = SwiftMessages/Identifiable.swift; sourceTree = ""; }; + 5CAB201AD00CAB811B045E2FFB5C03A8 /* Pods-iMessageExtensionDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-iMessageExtensionDemo-umbrella.h"; sourceTree = ""; }; + 60268FE48AA4DC9FD5060B1E5CE68453 /* errorIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIcon@2x.png"; path = "SwiftMessages/Resources/errorIcon@2x.png"; sourceTree = ""; }; + 62755A788F910CA88887B6F63BBC545F /* successIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIcon@2x.png"; path = "SwiftMessages/Resources/successIcon@2x.png"; sourceTree = ""; }; + 6489B2A759075E9DC1D1406734F45B5F /* Pods-iMessageExtensionDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-iMessageExtensionDemo.modulemap"; sourceTree = ""; }; + 6516EE9BFCB9C53C151359F9D0247562 /* infoIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconLight@2x.png"; path = "SwiftMessages/Resources/infoIconLight@2x.png"; sourceTree = ""; }; + 667DECE93ABCC6869A071FFEB0F83EA5 /* warningIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconSubtle@3x.png"; path = "SwiftMessages/Resources/warningIconSubtle@3x.png"; sourceTree = ""; }; + 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftMessages.debug.xcconfig; sourceTree = ""; }; + 70E7AB099F856140EF93D5B94A967418 /* infoIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIcon.png; path = SwiftMessages/Resources/infoIcon.png; sourceTree = ""; }; + 7241B2130D211F0832CCE4928CBB6486 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; path = README.md; sourceTree = ""; }; + 72A865FFBAE49EF66A35CB9D709E8D7E /* successIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconLight@3x.png"; path = "SwiftMessages/Resources/successIconLight@3x.png"; sourceTree = ""; }; + 79E38069364BC5DF4EA88F352E28B242 /* warningIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIconLight.png; path = SwiftMessages/Resources/warningIconLight.png; sourceTree = ""; }; + 7A6801849037A728E9BC50E06CE8AD2F /* StatusLine.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = StatusLine.xib; path = SwiftMessages/Resources/StatusLine.xib; sourceTree = ""; }; + 7A965DD26246DCA8CE39FBAB348ABA24 /* Presenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Presenter.swift; path = SwiftMessages/Presenter.swift; sourceTree = ""; }; + 7CC6A596A9C1659D8E93222DA4144414 /* Pods-iMessageExtensionDemo-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageExtensionDemo-Info.plist"; sourceTree = ""; }; + 7F40CA14AD738DD186B4DA8FD14AE5BD /* Pods-iMessageExtensionDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-iMessageExtensionDemo-dummy.m"; sourceTree = ""; }; + 7FCF161BD9F1C2CAAFBCADE5E59BD3FD /* NSBundle+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSBundle+Extensions.swift"; path = "SwiftMessages/NSBundle+Extensions.swift"; sourceTree = ""; }; + 820B743874F7AC9F9E3970D68E2E60FA /* Pods-iMessageDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageDemo.release.xcconfig"; sourceTree = ""; }; + 8341EF04E2B20C2BF6D4AF2240F80A56 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = SwiftMessages/Error.swift; sourceTree = ""; }; + 848251807107C20960A3DABAB27F7475 /* errorIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconLight@3x.png"; path = "SwiftMessages/Resources/errorIconLight@3x.png"; sourceTree = ""; }; + 874D31DE863C88B1D699E1EBFBE0641B /* warningIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconLight@2x.png"; path = "SwiftMessages/Resources/warningIconLight@2x.png"; sourceTree = ""; }; + 8901520225CE89F44E6DE88688F29C10 /* MessageView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MessageView.swift; path = SwiftMessages/MessageView.swift; sourceTree = ""; }; + 8D54691037F1CA4653B76F0558E2AA82 /* Pods-iMessageExtensionDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-iMessageExtensionDemo-acknowledgements.markdown"; sourceTree = ""; }; + 90F364E0C9A6EFE24680868D0BD293F1 /* SwiftMessages-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SwiftMessages-Info.plist"; sourceTree = ""; }; + 915DE2E4E300BAD440BE13F72E49D731 /* Pods-iMessageDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageDemo-acknowledgements.plist"; sourceTree = ""; }; + 9C110C924ED12D2D32ECC27503018A31 /* infoIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIconLight.png; path = SwiftMessages/Resources/infoIconLight.png; sourceTree = ""; }; + 9CF61FDEFE095F0486E9914F2262ADB9 /* MaskingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MaskingView.swift; path = SwiftMessages/MaskingView.swift; sourceTree = ""; }; + 9D1FEAC04417D847EDC10783E054988F /* errorIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIcon.png; path = SwiftMessages/Resources/errorIcon.png; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + A0D0E8B0020635F606875DD02735C502 /* BaseView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BaseView.swift; path = SwiftMessages/BaseView.swift; sourceTree = ""; }; + A2F9031B7FA82A17F04D4403091DF836 /* SwiftMessages-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SwiftMessages-dummy.m"; sourceTree = ""; }; + A3C32E945AE3E6394EF85CD6BEC714B4 /* SwiftMessages.Config+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SwiftMessages.Config+Extensions.swift"; path = "SwiftMessages/SwiftMessages.Config+Extensions.swift"; sourceTree = ""; }; + A80433B71162112A79043CB64261DB51 /* successIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIconLight.png; path = SwiftMessages/Resources/successIconLight.png; sourceTree = ""; }; + A850F76D7E3FEDC20FFB877454069171 /* errorIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIconSubtle.png; path = SwiftMessages/Resources/errorIconSubtle.png; sourceTree = ""; }; + A9A13E69643D651322647C28E3F9E9C9 /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIEdgeInsets+Extensions.swift"; path = "SwiftMessages/UIEdgeInsets+Extensions.swift"; sourceTree = ""; }; + AE62AA801971C530345349D18AFCCB82 /* MessageView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = MessageView.xib; path = SwiftMessages/Resources/MessageView.xib; sourceTree = ""; }; + AE7AEA9CE6B44DCC96AE4E68FA644DAA /* Pods-iMessageExtensionDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageExtensionDemo.release.xcconfig"; sourceTree = ""; }; + AFC41396FB1BD59C9A69EE1DD82E47C2 /* Pods_iMessageDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_iMessageDemo.framework; path = "Pods-iMessageDemo.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + AFFDB7DDC6B6B064B9D12281E2531BFA /* SwiftMessagesSegue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftMessagesSegue.swift; path = SwiftMessages/SwiftMessagesSegue.swift; sourceTree = ""; }; + B6DEAADC09FEB1A8D5B90108103EE478 /* errorIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIcon@3x.png"; path = "SwiftMessages/Resources/errorIcon@3x.png"; sourceTree = ""; }; + B7FD0618783A3E6B90D3A3323633959F /* TabView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = TabView.xib; path = SwiftMessages/Resources/TabView.xib; sourceTree = ""; }; + B91AD9D9E743D17D553D48103BE27C46 /* MarginAdjustable+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "MarginAdjustable+Extensions.swift"; path = "SwiftMessages/MarginAdjustable+Extensions.swift"; sourceTree = ""; }; + B99CBDE49D6502CF64EB9059C005BF31 /* Pods-iMessageDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageDemo.debug.xcconfig"; sourceTree = ""; }; + BEBF018059B0DFCAC8494ABD1C578AD9 /* SwiftMessages_SwiftMessages.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = SwiftMessages_SwiftMessages.bundle; path = "SwiftMessages-SwiftMessages_SwiftMessages.bundle"; sourceTree = BUILT_PRODUCTS_DIR; }; + BF61E78F8E8EE539F4A63C5A9D43AC15 /* Pods-iMessageDemo-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-iMessageDemo-frameworks.sh"; sourceTree = ""; }; + BFEF746702215C33B51BEE64C4E48F0A /* warningIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIcon@2x.png"; path = "SwiftMessages/Resources/warningIcon@2x.png"; sourceTree = ""; }; + C17CFEF9B761A322945F74D86CA88036 /* warningIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconLight@3x.png"; path = "SwiftMessages/Resources/warningIconLight@3x.png"; sourceTree = ""; }; + C306ACAFEE157959D78E71DBBBD675DC /* Pods-iMessageExtensionDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageExtensionDemo.debug.xcconfig"; sourceTree = ""; }; + C3216CF40D770C387D45C3B4AF2CC9E0 /* SwiftMessages.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftMessages.swift; path = SwiftMessages/SwiftMessages.swift; sourceTree = ""; }; + C614EECDDFE644AF0BF7CB16A3D74404 /* SwiftMessages-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftMessages-umbrella.h"; sourceTree = ""; }; + C6C56947CAF8EFCC7858E1E2F1273427 /* MarginAdjustable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MarginAdjustable.swift; path = SwiftMessages/MarginAdjustable.swift; sourceTree = ""; }; + C7FE39695CB7C6997ACA39C8680B414A /* SwiftMessages.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = SwiftMessages.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + C8155ED78358FA5CF39089176FBDE501 /* successIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIcon@3x.png"; path = "SwiftMessages/Resources/successIcon@3x.png"; sourceTree = ""; }; + C9D915B60769D3C45A0DA3A5BA9514B8 /* ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist"; sourceTree = ""; }; + CAB58A9F688DD39112E6CDF20C8969C0 /* BackgroundViewable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BackgroundViewable.swift; path = SwiftMessages/BackgroundViewable.swift; sourceTree = ""; }; + CBC3F501D8BC852716D085B3022E68CA /* Pods_iMessageExtensionDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_iMessageExtensionDemo.framework; path = "Pods-iMessageExtensionDemo.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + CC9152C843976F18EF9AE005786DCC80 /* Pods-iMessageDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-iMessageDemo.modulemap"; sourceTree = ""; }; + D245E0514AAC1A2B9A6D5EA2F383E90F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + D5607E285A85AC7163B0B8FD447FD27E /* Theme.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Theme.swift; path = SwiftMessages/Theme.swift; sourceTree = ""; }; + D7C557E1DC95AFA417E94ED01301F9F2 /* PassthroughView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PassthroughView.swift; path = SwiftMessages/PassthroughView.swift; sourceTree = ""; }; + E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftMessages.release.xcconfig; sourceTree = ""; }; + E473E4F019E816262A61B7F5E8B42373 /* Pods-iMessageDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-iMessageDemo-acknowledgements.markdown"; sourceTree = ""; }; + EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + ED86D7B42F55040DCE162653FB3C7EDB /* warningIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconSubtle@2x.png"; path = "SwiftMessages/Resources/warningIconSubtle@2x.png"; sourceTree = ""; }; + EDDAF8A2C45FDDDFD5AFA59203137551 /* AccessibleMessage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AccessibleMessage.swift; path = SwiftMessages/AccessibleMessage.swift; sourceTree = ""; }; + F7004673F1B51EEC365B32F0E060E564 /* infoIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIcon@2x.png"; path = "SwiftMessages/Resources/infoIcon@2x.png"; sourceTree = ""; }; + F898B2AC5C3404C266BBCA3B6D22B5E4 /* successIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconLight@2x.png"; path = "SwiftMessages/Resources/successIconLight@2x.png"; sourceTree = ""; }; + FC73E6C784AF6CA1F956F57F82ED2803 /* successIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIcon.png; path = SwiftMessages/Resources/successIcon.png; sourceTree = ""; }; + FCDC8870EA94B5B1E966D34D2B1FA5FE /* SwiftMessages-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftMessages-prefix.pch"; sourceTree = ""; }; + FE3BED1799B2F867F5C984C2A051E36A /* PhysicsAnimation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PhysicsAnimation.swift; path = SwiftMessages/PhysicsAnimation.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 495E35DFE0854ABB7E2A238D1CFC4550 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C3CDAED707B153A58674CB1AC4A33FB2 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C3AABE927CAF3C6135B4D37CA433F885 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F2C6C6F4FCF31DEB85ADCA0DE9EF6EEC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A9EB0C8E49AB748B05CF7941ACAF8475 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FA7AA2A57B110DEF3C1F616FA77A05A7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8148CD8F2B38FB38B7B9CCC12E93ECFB /* Foundation.framework in Frameworks */, + E88597F65A00A5AF50EEF2ABA2392B2F /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 59DA5C1F72E1D5BABC43EACBA672C3BA /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 423F06E259421657656F08FC805160BA /* Products */ = { + isa = PBXGroup; + children = ( + AFC41396FB1BD59C9A69EE1DD82E47C2 /* Pods_iMessageDemo.framework */, + CBC3F501D8BC852716D085B3022E68CA /* Pods_iMessageExtensionDemo.framework */, + 4824F23D80FF9070A5F8A452DB11EB9A /* SwiftMessages.framework */, + BEBF018059B0DFCAC8494ABD1C578AD9 /* SwiftMessages_SwiftMessages.bundle */, + ); + name = Products; + sourceTree = ""; + }; + 59DA5C1F72E1D5BABC43EACBA672C3BA /* iOS */ = { + isa = PBXGroup; + children = ( + EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */, + D245E0514AAC1A2B9A6D5EA2F383E90F /* UIKit.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 8F3CF4AFB0CA47B3BFE1C68E51CDF0A9 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 9A912CA1E54EADE1787311C1DF7E8F2E /* Pods-iMessageDemo */, + BD13800F87C70DC802DBC0C37E8C5E99 /* Pods-iMessageExtensionDemo */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 9A632FB0C8554E0688B34926AF9C52DB /* SwiftMessages */ = { + isa = PBXGroup; + children = ( + AD776BCEA093D43499821A6E4251BF03 /* AppExtension */, + A58DF9B1678B5C3CCA8A840C72186044 /* Pod */, + B3699CF01F28F4B75166BA983453EAF3 /* Support Files */, + ); + name = SwiftMessages; + path = ../..; + sourceTree = ""; + }; + 9A912CA1E54EADE1787311C1DF7E8F2E /* Pods-iMessageDemo */ = { + isa = PBXGroup; + children = ( + CC9152C843976F18EF9AE005786DCC80 /* Pods-iMessageDemo.modulemap */, + E473E4F019E816262A61B7F5E8B42373 /* Pods-iMessageDemo-acknowledgements.markdown */, + 915DE2E4E300BAD440BE13F72E49D731 /* Pods-iMessageDemo-acknowledgements.plist */, + 14BF989232A1D55A0FDAAB70B5A8E1BF /* Pods-iMessageDemo-dummy.m */, + BF61E78F8E8EE539F4A63C5A9D43AC15 /* Pods-iMessageDemo-frameworks.sh */, + 093D5BBE2A96A1A7AC0432A3AB933576 /* Pods-iMessageDemo-Info.plist */, + 2D0ECE831FB5E0EE1D68E837671320C7 /* Pods-iMessageDemo-umbrella.h */, + B99CBDE49D6502CF64EB9059C005BF31 /* Pods-iMessageDemo.debug.xcconfig */, + 820B743874F7AC9F9E3970D68E2E60FA /* Pods-iMessageDemo.release.xcconfig */, + ); + name = "Pods-iMessageDemo"; + path = "Target Support Files/Pods-iMessageDemo"; + sourceTree = ""; + }; + A58DF9B1678B5C3CCA8A840C72186044 /* Pod */ = { + isa = PBXGroup; + children = ( + 2B6B36CBE6DC07B2F005E30EA2B121CB /* LICENSE.md */, + 7241B2130D211F0832CCE4928CBB6486 /* README.md */, + C7FE39695CB7C6997ACA39C8680B414A /* SwiftMessages.podspec */, + ); + name = Pod; + sourceTree = ""; + }; + AD776BCEA093D43499821A6E4251BF03 /* AppExtension */ = { + isa = PBXGroup; + children = ( + EDDAF8A2C45FDDDFD5AFA59203137551 /* AccessibleMessage.swift */, + 267E35F9851AAE50DFB8FA0DCA7F2980 /* Animator.swift */, + CAB58A9F688DD39112E6CDF20C8969C0 /* BackgroundViewable.swift */, + A0D0E8B0020635F606875DD02735C502 /* BaseView.swift */, + 19B5EF40CEC1F6DB23F428DC159D4BC2 /* CALayer+Extensions.swift */, + 42F1E753E61B6EDED3908AC66994649C /* CardView.xib */, + 3DF091E68C4659506DB08B0876BD274C /* CenteredView.xib */, + 4F8D7902822221456B697BB41111E450 /* CornerRoundingView.swift */, + 8341EF04E2B20C2BF6D4AF2240F80A56 /* Error.swift */, + 9D1FEAC04417D847EDC10783E054988F /* errorIcon.png */, + 60268FE48AA4DC9FD5060B1E5CE68453 /* errorIcon@2x.png */, + B6DEAADC09FEB1A8D5B90108103EE478 /* errorIcon@3x.png */, + 0892E032AE12339D1AD84BDCC78A3C07 /* errorIconLight.png */, + 1B04615682E8B787C964824435BC6616 /* errorIconLight@2x.png */, + 848251807107C20960A3DABAB27F7475 /* errorIconLight@3x.png */, + A850F76D7E3FEDC20FFB877454069171 /* errorIconSubtle.png */, + 3C313FB1D33EF4B477FD5D3D6179A8BE /* errorIconSubtle@2x.png */, + 453BC098B6A052020C40DE576F684C7B /* errorIconSubtle@3x.png */, + 5C0DE01AB7D0935933E7AFBDF2945814 /* Identifiable.swift */, + 70E7AB099F856140EF93D5B94A967418 /* infoIcon.png */, + F7004673F1B51EEC365B32F0E060E564 /* infoIcon@2x.png */, + 337B3108412E3812254B85BCC4F90EB8 /* infoIcon@3x.png */, + 9C110C924ED12D2D32ECC27503018A31 /* infoIconLight.png */, + 6516EE9BFCB9C53C151359F9D0247562 /* infoIconLight@2x.png */, + 4412F313361EFEE7A0193533A5AC5999 /* infoIconLight@3x.png */, + 06F2F626BE8417F1806CC5B17F210C90 /* infoIconSubtle.png */, + 4FE466AC4123CDAE9FDA9FCF4FB9CC60 /* infoIconSubtle@2x.png */, + 2B7213B7DC5432DA2B272F25E17AA364 /* infoIconSubtle@3x.png */, + 536660614870EA0E051BF6BDDF495798 /* KeyboardTrackingView.swift */, + C6C56947CAF8EFCC7858E1E2F1273427 /* MarginAdjustable.swift */, + B91AD9D9E743D17D553D48103BE27C46 /* MarginAdjustable+Extensions.swift */, + 9CF61FDEFE095F0486E9914F2262ADB9 /* MaskingView.swift */, + 8901520225CE89F44E6DE88688F29C10 /* MessageView.swift */, + AE62AA801971C530345349D18AFCCB82 /* MessageView.xib */, + 7FCF161BD9F1C2CAAFBCADE5E59BD3FD /* NSBundle+Extensions.swift */, + 0970322A5DD8B4A8373C35ED051DE156 /* NSLayoutConstraint+Extensions.swift */, + D7C557E1DC95AFA417E94ED01301F9F2 /* PassthroughView.swift */, + 382E6375390EBB09F829519F8ACCB7D7 /* PassthroughWindow.swift */, + FE3BED1799B2F867F5C984C2A051E36A /* PhysicsAnimation.swift */, + 2337E6D5F621F3CE9A1E3761984EBE87 /* PhysicsPanHandler.swift */, + 7A965DD26246DCA8CE39FBAB348ABA24 /* Presenter.swift */, + 7A6801849037A728E9BC50E06CE8AD2F /* StatusLine.xib */, + FC73E6C784AF6CA1F956F57F82ED2803 /* successIcon.png */, + 62755A788F910CA88887B6F63BBC545F /* successIcon@2x.png */, + C8155ED78358FA5CF39089176FBDE501 /* successIcon@3x.png */, + A80433B71162112A79043CB64261DB51 /* successIconLight.png */, + F898B2AC5C3404C266BBCA3B6D22B5E4 /* successIconLight@2x.png */, + 72A865FFBAE49EF66A35CB9D709E8D7E /* successIconLight@3x.png */, + 1DC54BB09EFDFEDE11F484FE73BEDC60 /* successIconSubtle.png */, + 0B3A169D83BDA3613A661845D1607FC0 /* successIconSubtle@2x.png */, + 54B278C80D821C120FA70ABB6CAF1F46 /* successIconSubtle@3x.png */, + C3216CF40D770C387D45C3B4AF2CC9E0 /* SwiftMessages.swift */, + A3C32E945AE3E6394EF85CD6BEC714B4 /* SwiftMessages.Config+Extensions.swift */, + AFFDB7DDC6B6B064B9D12281E2531BFA /* SwiftMessagesSegue.swift */, + B7FD0618783A3E6B90D3A3323633959F /* TabView.xib */, + D5607E285A85AC7163B0B8FD447FD27E /* Theme.swift */, + 396FCF260E9C2B3F11080A91E3D72334 /* TopBottomAnimation.swift */, + A9A13E69643D651322647C28E3F9E9C9 /* UIEdgeInsets+Extensions.swift */, + 15C4C88778A19C193D1EC77FA77BAE4C /* UIViewController+Extensions.swift */, + 397C8F928170138667B9326F9655D75D /* UIWindow+Extensions.swift */, + 0259757860B26C6072E2640B84EC6D45 /* warningIcon.png */, + BFEF746702215C33B51BEE64C4E48F0A /* warningIcon@2x.png */, + 2CFBBC25592C97C925B6F81B53BE57CB /* warningIcon@3x.png */, + 79E38069364BC5DF4EA88F352E28B242 /* warningIconLight.png */, + 874D31DE863C88B1D699E1EBFBE0641B /* warningIconLight@2x.png */, + C17CFEF9B761A322945F74D86CA88036 /* warningIconLight@3x.png */, + 4512DEEA328AB0AAA95D77C84C89E02C /* warningIconSubtle.png */, + ED86D7B42F55040DCE162653FB3C7EDB /* warningIconSubtle@2x.png */, + 667DECE93ABCC6869A071FFEB0F83EA5 /* warningIconSubtle@3x.png */, + 2E6941E59EF0D89949E3DF3D89488430 /* Weak.swift */, + 0A8566413BFA3FE6827E63E30515C9B3 /* WindowViewController.swift */, + ); + name = AppExtension; + sourceTree = ""; + }; + B3699CF01F28F4B75166BA983453EAF3 /* Support Files */ = { + isa = PBXGroup; + children = ( + C9D915B60769D3C45A0DA3A5BA9514B8 /* ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist */, + 346718C2C7A108C86535F89FEB0EC176 /* SwiftMessages.modulemap */, + A2F9031B7FA82A17F04D4403091DF836 /* SwiftMessages-dummy.m */, + 90F364E0C9A6EFE24680868D0BD293F1 /* SwiftMessages-Info.plist */, + FCDC8870EA94B5B1E966D34D2B1FA5FE /* SwiftMessages-prefix.pch */, + C614EECDDFE644AF0BF7CB16A3D74404 /* SwiftMessages-umbrella.h */, + 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */, + E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */, + ); + name = "Support Files"; + path = "iMessageDemo/Pods/Target Support Files/SwiftMessages"; + sourceTree = ""; + }; + BD13800F87C70DC802DBC0C37E8C5E99 /* Pods-iMessageExtensionDemo */ = { + isa = PBXGroup; + children = ( + 6489B2A759075E9DC1D1406734F45B5F /* Pods-iMessageExtensionDemo.modulemap */, + 8D54691037F1CA4653B76F0558E2AA82 /* Pods-iMessageExtensionDemo-acknowledgements.markdown */, + 1341BB7116EC50FDF7062C6A91DEDF49 /* Pods-iMessageExtensionDemo-acknowledgements.plist */, + 7F40CA14AD738DD186B4DA8FD14AE5BD /* Pods-iMessageExtensionDemo-dummy.m */, + 7CC6A596A9C1659D8E93222DA4144414 /* Pods-iMessageExtensionDemo-Info.plist */, + 5CAB201AD00CAB811B045E2FFB5C03A8 /* Pods-iMessageExtensionDemo-umbrella.h */, + C306ACAFEE157959D78E71DBBBD675DC /* Pods-iMessageExtensionDemo.debug.xcconfig */, + AE7AEA9CE6B44DCC96AE4E68FA644DAA /* Pods-iMessageExtensionDemo.release.xcconfig */, + ); + name = "Pods-iMessageExtensionDemo"; + path = "Target Support Files/Pods-iMessageExtensionDemo"; + sourceTree = ""; + }; + C5AAA95D48373FAC474F6EFCC1749444 /* Development Pods */ = { + isa = PBXGroup; + children = ( + 9A632FB0C8554E0688B34926AF9C52DB /* SwiftMessages */, + ); + name = "Development Pods"; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + C5AAA95D48373FAC474F6EFCC1749444 /* Development Pods */, + 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */, + 423F06E259421657656F08FC805160BA /* Products */, + 8F3CF4AFB0CA47B3BFE1C68E51CDF0A9 /* Targets Support Files */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 96A1C098516CB9F20C4BE19860673FA7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 560A2B1056FEFE42AC6524A2A1742CA2 /* Pods-iMessageExtensionDemo-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AEC231A576EA094C9EF913D75BA2D69C /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7BC52E6F0D9D19B05E62E623E53FCE82 /* Pods-iMessageDemo-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B534C45C1A426DF58D21D75F281F983A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 9E3D4CA932041E99B6FD56D4E79A726F /* SwiftMessages-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 1FC5E8328653C350899229BDF89FACE5 /* SwiftMessages-SwiftMessages_SwiftMessages */ = { + isa = PBXNativeTarget; + buildConfigurationList = 57E1F5473FEF9FC2401E805CCF8188C3 /* Build configuration list for PBXNativeTarget "SwiftMessages-SwiftMessages_SwiftMessages" */; + buildPhases = ( + 5FA15A9B2968910DC30C1AC895A5397A /* Sources */, + C3AABE927CAF3C6135B4D37CA433F885 /* Frameworks */, + F8808FE568E0B01931D6216DF79110B1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SwiftMessages-SwiftMessages_SwiftMessages"; + productName = "SwiftMessages-SwiftMessages_SwiftMessages"; + productReference = BEBF018059B0DFCAC8494ABD1C578AD9 /* SwiftMessages_SwiftMessages.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 2757367020CF4EA7726D56118C89F6AE /* Pods-iMessageExtensionDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = ED0C46CBFB7B22526D6F384198E16114 /* Build configuration list for PBXNativeTarget "Pods-iMessageExtensionDemo" */; + buildPhases = ( + 96A1C098516CB9F20C4BE19860673FA7 /* Headers */, + 26079E47AEA7D168B2259F29AF1AE73B /* Sources */, + 495E35DFE0854ABB7E2A238D1CFC4550 /* Frameworks */, + B1A8F08DE3F2C1EF1D63EF29C9D3D327 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BB9BD3F204FD8449B62AD70E23DABC13 /* PBXTargetDependency */, + ); + name = "Pods-iMessageExtensionDemo"; + productName = "Pods-iMessageExtensionDemo"; + productReference = CBC3F501D8BC852716D085B3022E68CA /* Pods_iMessageExtensionDemo.framework */; + productType = "com.apple.product-type.framework"; + }; + DAB613A18652334F6BFC5F27BADF515D /* SwiftMessages */ = { + isa = PBXNativeTarget; + buildConfigurationList = ABCC3636B5EAEBE6D60D155704F40EBC /* Build configuration list for PBXNativeTarget "SwiftMessages" */; + buildPhases = ( + B534C45C1A426DF58D21D75F281F983A /* Headers */, + ABE787B29A89D2BB29F92EAE5C8526CF /* Sources */, + FA7AA2A57B110DEF3C1F616FA77A05A7 /* Frameworks */, + C69D4A2DC76A80BD6D45A9BE85B2EEB1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 03EC5F5CF0CAA96E132B778FB51EBCE9 /* PBXTargetDependency */, + ); + name = SwiftMessages; + productName = SwiftMessages; + productReference = 4824F23D80FF9070A5F8A452DB11EB9A /* SwiftMessages.framework */; + productType = "com.apple.product-type.framework"; + }; + E2AECC8B9DD9E437C7DD0FD0FFC881F3 /* Pods-iMessageDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 20A82A14E31D7EFF5BE9B60529162F4B /* Build configuration list for PBXNativeTarget "Pods-iMessageDemo" */; + buildPhases = ( + AEC231A576EA094C9EF913D75BA2D69C /* Headers */, + 41C8F9B8F0E317E193B01E8DC96E6F02 /* Sources */, + F2C6C6F4FCF31DEB85ADCA0DE9EF6EEC /* Frameworks */, + 61DB2F41473C1B8FEA6385AA240E2586 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 3CF465B66D2B58FC406E66E621CBCB11 /* PBXTargetDependency */, + ); + name = "Pods-iMessageDemo"; + productName = "Pods-iMessageDemo"; + productReference = AFC41396FB1BD59C9A69EE1DD82E47C2 /* Pods_iMessageDemo.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1100; + LastUpgradeCheck = 1100; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = 423F06E259421657656F08FC805160BA /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E2AECC8B9DD9E437C7DD0FD0FFC881F3 /* Pods-iMessageDemo */, + 2757367020CF4EA7726D56118C89F6AE /* Pods-iMessageExtensionDemo */, + DAB613A18652334F6BFC5F27BADF515D /* SwiftMessages */, + 1FC5E8328653C350899229BDF89FACE5 /* SwiftMessages-SwiftMessages_SwiftMessages */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 61DB2F41473C1B8FEA6385AA240E2586 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B1A8F08DE3F2C1EF1D63EF29C9D3D327 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C69D4A2DC76A80BD6D45A9BE85B2EEB1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 425F2D4CE95436680D77C263FF15221B /* SwiftMessages_SwiftMessages.bundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F8808FE568E0B01931D6216DF79110B1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4E9CCFC43646B6CDBE3B787AB09A0147 /* CardView.xib in Resources */, + F27E3EEAFDDAA6CB4E7407D6A46DAA5D /* CenteredView.xib in Resources */, + 5260BD3289BAC54A20457099C4A57EFF /* errorIcon.png in Resources */, + 683A7897D1E9A73F4717198B1C054D29 /* errorIcon@2x.png in Resources */, + 6A539682FDDA0E5DA23E1B5F2BA133C1 /* errorIcon@3x.png in Resources */, + 4E703B2A80C64CF1142872BE31263940 /* errorIconLight.png in Resources */, + 1F4159921A25C7B2A0E9C587387D829C /* errorIconLight@2x.png in Resources */, + 4C78ED4E1780F5609E25CE03429C1DE4 /* errorIconLight@3x.png in Resources */, + 365594AAFDD4EE947EB33E6E86A8578E /* errorIconSubtle.png in Resources */, + EDA146BF3FF59593677F8B2AA785D8A5 /* errorIconSubtle@2x.png in Resources */, + D8BDC20F1566606BF64001B6E96B14B6 /* errorIconSubtle@3x.png in Resources */, + C5FFE932D5EBE2CC8F2ABFEA893D8E9C /* infoIcon.png in Resources */, + B2CC8FF0F9FF3FE929180CDB32B69F18 /* infoIcon@2x.png in Resources */, + B60094A8D1343B7351F0EF9C51F2F0DB /* infoIcon@3x.png in Resources */, + 5720D965B3CE67653082137053FBEC9C /* infoIconLight.png in Resources */, + D61D59BCDFD2C3C7993CFE883DE60692 /* infoIconLight@2x.png in Resources */, + 9FFE65CB6E825ECAE4838D53E7BA4C06 /* infoIconLight@3x.png in Resources */, + C4598A458697C49C961BFDCD090B3A8F /* infoIconSubtle.png in Resources */, + 2B23A9DFDAACFE9C0AD5EB6899E63475 /* infoIconSubtle@2x.png in Resources */, + 7ACCA07CCFD868899D61F4B4AE5774DB /* infoIconSubtle@3x.png in Resources */, + 2558CABB502ED605BC21DCFC55A9C0B7 /* MessageView.xib in Resources */, + 492F085489FCAB0EEBE74B098F7D3F4D /* StatusLine.xib in Resources */, + 462CDC24C5C8DD6905C4112B6B4BD2ED /* successIcon.png in Resources */, + B42A7A38C8014DBDE2632B909F71C355 /* successIcon@2x.png in Resources */, + 44C0F194D748EE88027414A5B2094E9B /* successIcon@3x.png in Resources */, + 138A7742F76993FB9EE3555FD2808562 /* successIconLight.png in Resources */, + BDCF9C5E4F88B2B0AB6D4595E5A281E1 /* successIconLight@2x.png in Resources */, + 33785D52B8888C2EA02BD0495408E352 /* successIconLight@3x.png in Resources */, + AC4F13F50EB63B484292D67692BC1F9D /* successIconSubtle.png in Resources */, + BBFE3BAFFCE67F4EACE0C67A7B7FFC3A /* successIconSubtle@2x.png in Resources */, + 5DF3F4808ED4A6932839C11A5D742B93 /* successIconSubtle@3x.png in Resources */, + 57072960EA4F0D307171ED90697D3FAF /* TabView.xib in Resources */, + 447E8A096C1ABD2E0AC9674E65A827E3 /* warningIcon.png in Resources */, + BB16D1E73A5D6B27DC4212926986107F /* warningIcon@2x.png in Resources */, + 64595C731B826EB19E9757D524E0BF76 /* warningIcon@3x.png in Resources */, + CCF5CC8F6022DFD410DDCC99A90D58B0 /* warningIconLight.png in Resources */, + 4DB5D1FB08693DDDC32BCF19CC1B1AA0 /* warningIconLight@2x.png in Resources */, + C6E73F201545CF5ED055C69CD4DB2EFF /* warningIconLight@3x.png in Resources */, + 1F6162906845BE72A5BCDAF14D6E14B9 /* warningIconSubtle.png in Resources */, + 89ACEF0F9E524BD21D6C2460FEC375F8 /* warningIconSubtle@2x.png in Resources */, + 755DA479621A9D2BB8B84540DE648A7A /* warningIconSubtle@3x.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 26079E47AEA7D168B2259F29AF1AE73B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 46CCA4DDFDBBDD2A9426BB96C08E4255 /* Pods-iMessageExtensionDemo-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 41C8F9B8F0E317E193B01E8DC96E6F02 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C384FB76A48C06F7581D0F7850F2F4F1 /* Pods-iMessageDemo-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5FA15A9B2968910DC30C1AC895A5397A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + ABE787B29A89D2BB29F92EAE5C8526CF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A11E7A379B288CCA3AE6785B83FA4316 /* AccessibleMessage.swift in Sources */, + 44150A4B5B2D251FCBB6CA07DC9872B5 /* Animator.swift in Sources */, + E94E8711BDDA31B178AA032D3346C307 /* BackgroundViewable.swift in Sources */, + 4267FACE20717FF3F51C2ACAB8C395A4 /* BaseView.swift in Sources */, + D49E06426C51C49E9058371138972A69 /* CALayer+Extensions.swift in Sources */, + 6320AE79D41E8D1F52AF66A670542561 /* CornerRoundingView.swift in Sources */, + A1734DB0A8A558B2397AF54E63F64416 /* Error.swift in Sources */, + FCB6832EB4D32EF085E770E8B4A9BC2C /* Identifiable.swift in Sources */, + 3505AB28DBFA49FBE5C8250F3E067E60 /* KeyboardTrackingView.swift in Sources */, + 0E7AE1B3CE2734B39ACCE812B4320B44 /* MarginAdjustable+Extensions.swift in Sources */, + 966B9C1EE6B73E430F03D51A4FD26D20 /* MarginAdjustable.swift in Sources */, + 5750C24C3A9CAE11C7E36B37434912D0 /* MaskingView.swift in Sources */, + 0B42A04122166EAD384BCE37FD450FAF /* MessageView.swift in Sources */, + 461760E2818D72B948B60B4835E7B1ED /* NSBundle+Extensions.swift in Sources */, + 16047C447B00FAA7F42764EC4167C33B /* NSLayoutConstraint+Extensions.swift in Sources */, + 0CE00BF7FB0F6376D89B0AFF1CFD7510 /* PassthroughView.swift in Sources */, + C8F46E0A5853739D3F632B4828FDE9CC /* PassthroughWindow.swift in Sources */, + 7E5ADF1F3B6849D5A0DF8E2B9C1861C5 /* PhysicsAnimation.swift in Sources */, + 0303F738260F2C9BAE20B79DE84E82BC /* PhysicsPanHandler.swift in Sources */, + FF01BC94FADD5A72282AEE043DF523A7 /* Presenter.swift in Sources */, + FA6CA270F521DF68A75E527954A2DDAD /* SwiftMessages-dummy.m in Sources */, + F50FE2EE47422AD39AC8F7F115081E7E /* SwiftMessages.Config+Extensions.swift in Sources */, + B2862C6DDAA6543BB2C8F4541F044564 /* SwiftMessages.swift in Sources */, + 9CEE0E569456D932AA34329D2038DF98 /* SwiftMessagesSegue.swift in Sources */, + 2181E713FC7C00EE871FDA6CB62C7E8C /* Theme.swift in Sources */, + BC4618CE535404A9540D4D110B5767A1 /* TopBottomAnimation.swift in Sources */, + 52F4ED7F78829270B2AFE5EDBA9EEE2F /* UIEdgeInsets+Extensions.swift in Sources */, + D9077478C2FCD7C3DD1EBE9373281728 /* UIViewController+Extensions.swift in Sources */, + 6C7DAA6A68AFDACD67F2C127CEF4DD6F /* UIWindow+Extensions.swift in Sources */, + 00468531530F8A70E3D83622BD482026 /* Weak.swift in Sources */, + F5642C087197B9033252FF10FBA92B59 /* WindowViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 03EC5F5CF0CAA96E132B778FB51EBCE9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "SwiftMessages-SwiftMessages_SwiftMessages"; + target = 1FC5E8328653C350899229BDF89FACE5 /* SwiftMessages-SwiftMessages_SwiftMessages */; + targetProxy = 141E78A8858DBF8B2695DFEDCBDF5158 /* PBXContainerItemProxy */; + }; + 3CF465B66D2B58FC406E66E621CBCB11 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SwiftMessages; + target = DAB613A18652334F6BFC5F27BADF515D /* SwiftMessages */; + targetProxy = 4DB1DDB02425E67ED85C70C3B138E205 /* PBXContainerItemProxy */; + }; + BB9BD3F204FD8449B62AD70E23DABC13 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SwiftMessages; + target = DAB613A18652334F6BFC5F27BADF515D /* SwiftMessages */; + targetProxy = 900F05D1477FFAB64FF410CBB6B9B74D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 24D1D8F3B822E3083FF435C91CB434FD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/SwiftMessages"; + IBSC_MODULE = SwiftMessages; + INFOPLIST_FILE = "Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = SwiftMessages_SwiftMessages; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 6427804744C4054555383985007A0B6C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + 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 = ( + "POD_CONFIGURATION_DEBUG=1", + "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 = 11.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 74556EDEC03158A3009CA84D67369133 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=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 = 11.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + 7C5AE2DF0A930DD6AC66390486478632 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/SwiftMessages/SwiftMessages-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SwiftMessages/SwiftMessages-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/SwiftMessages/SwiftMessages.modulemap"; + PRODUCT_MODULE_NAME = SwiftMessages; + PRODUCT_NAME = SwiftMessages; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 891563622FB1DE05CD4905BE16203F07 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C306ACAFEE157959D78E71DBBBD675DC /* Pods-iMessageExtensionDemo.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + A1CD8FCA9657A138B144BC1F2AABADD3 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AE7AEA9CE6B44DCC96AE4E68FA644DAA /* Pods-iMessageExtensionDemo.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + BCFFE899A2E9C1DF0CA120A3F3CECECC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/SwiftMessages"; + IBSC_MODULE = SwiftMessages; + INFOPLIST_FILE = "Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = SwiftMessages_SwiftMessages; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + C9423D1E13393A1A8BC54BE4E87A96AD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 820B743874F7AC9F9E3970D68E2E60FA /* Pods-iMessageDemo.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + F069CD2F5774D5082336F140E5F68B3A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/SwiftMessages/SwiftMessages-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SwiftMessages/SwiftMessages-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/SwiftMessages/SwiftMessages.modulemap"; + PRODUCT_MODULE_NAME = SwiftMessages; + PRODUCT_NAME = SwiftMessages; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + FCA0FCAB93E530D2C6BED8D3910FEB4A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B99CBDE49D6502CF64EB9059C005BF31 /* Pods-iMessageDemo.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = "Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 20A82A14E31D7EFF5BE9B60529162F4B /* Build configuration list for PBXNativeTarget "Pods-iMessageDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FCA0FCAB93E530D2C6BED8D3910FEB4A /* Debug */, + C9423D1E13393A1A8BC54BE4E87A96AD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6427804744C4054555383985007A0B6C /* Debug */, + 74556EDEC03158A3009CA84D67369133 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 57E1F5473FEF9FC2401E805CCF8188C3 /* Build configuration list for PBXNativeTarget "SwiftMessages-SwiftMessages_SwiftMessages" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 24D1D8F3B822E3083FF435C91CB434FD /* Debug */, + BCFFE899A2E9C1DF0CA120A3F3CECECC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + ABCC3636B5EAEBE6D60D155704F40EBC /* Build configuration list for PBXNativeTarget "SwiftMessages" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F069CD2F5774D5082336F140E5F68B3A /* Debug */, + 7C5AE2DF0A930DD6AC66390486478632 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + ED0C46CBFB7B22526D6F384198E16114 /* Build configuration list for PBXNativeTarget "Pods-iMessageExtensionDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 891563622FB1DE05CD4905BE16203F07 /* Debug */, + A1CD8FCA9657A138B144BC1F2AABADD3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-Info.plist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-Info.plist new file mode 100644 index 00000000..2243fe6e --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.markdown b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.markdown new file mode 100644 index 00000000..cfe94293 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.markdown @@ -0,0 +1,14 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## SwiftMessages + +Copyright (c) 2016 SwiftKick Mobile LLC + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Generated by CocoaPods - https://cocoapods.org diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.plist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.plist new file mode 100644 index 00000000..25aea9b0 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-acknowledgements.plist @@ -0,0 +1,46 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2016 SwiftKick Mobile LLC + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + License + MIT + Title + SwiftMessages + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-dummy.m b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-dummy.m new file mode 100644 index 00000000..2d3a72b7 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_iMessageDemo : NSObject +@end +@implementation PodsDummy_Pods_iMessageDemo +@end diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-input-files.xcfilelist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-input-files.xcfilelist new file mode 100644 index 00000000..c2649f16 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks.sh +${BUILT_PRODUCTS_DIR}/SwiftMessages/SwiftMessages.framework \ No newline at end of file diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-output-files.xcfilelist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-output-files.xcfilelist new file mode 100644 index 00000000..7e50d50f --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Debug-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftMessages.framework \ No newline at end of file diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-input-files.xcfilelist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-input-files.xcfilelist new file mode 100644 index 00000000..c2649f16 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks.sh +${BUILT_PRODUCTS_DIR}/SwiftMessages/SwiftMessages.framework \ No newline at end of file diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-output-files.xcfilelist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-output-files.xcfilelist new file mode 100644 index 00000000..7e50d50f --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-Release-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftMessages.framework \ No newline at end of file diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks.sh b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks.sh new file mode 100755 index 00000000..c735166d --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks.sh @@ -0,0 +1,185 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +BCSYMBOLMAP_DIR="BCSymbolMaps" + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then + # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied + find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do + echo "Installing $f" + install_bcsymbolmap "$f" "$destination" + rm "$f" + done + rmdir "${source}/${BCSYMBOLMAP_DIR}" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + warn_missing_arch=${2:-true} + if [ -r "$source" ]; then + # Copy the dSYM into the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .dSYM "$source")" + binary_name="$(ls "$source/Contents/Resources/DWARF")" + binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" + + # Strip invalid architectures from the dSYM. + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" "$warn_missing_arch" + fi + if [[ $STRIP_BINARY_RETVAL == 0 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" + fi + fi +} + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + warn_missing_arch=${2:-true} + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + if [[ "$warn_missing_arch" == "true" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + fi + STRIP_BINARY_RETVAL=1 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=0 +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/SwiftMessages/SwiftMessages.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/SwiftMessages/SwiftMessages.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-umbrella.h b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-umbrella.h new file mode 100644 index 00000000..2e129a27 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_iMessageDemoVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_iMessageDemoVersionString[]; + diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.debug.xcconfig b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.debug.xcconfig new file mode 100644 index 00000000..7d10f708 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.debug.xcconfig @@ -0,0 +1,14 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages/SwiftMessages.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "SwiftMessages" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.modulemap b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.modulemap new file mode 100644 index 00000000..980c725a --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.modulemap @@ -0,0 +1,6 @@ +framework module Pods_iMessageDemo { + umbrella header "Pods-iMessageDemo-umbrella.h" + + export * + module * { export * } +} diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.release.xcconfig b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.release.xcconfig new file mode 100644 index 00000000..7d10f708 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.release.xcconfig @@ -0,0 +1,14 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages/SwiftMessages.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "SwiftMessages" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-Info.plist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-Info.plist new file mode 100644 index 00000000..2243fe6e --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.markdown b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.markdown new file mode 100644 index 00000000..cfe94293 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.markdown @@ -0,0 +1,14 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## SwiftMessages + +Copyright (c) 2016 SwiftKick Mobile LLC + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Generated by CocoaPods - https://cocoapods.org diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.plist b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.plist new file mode 100644 index 00000000..25aea9b0 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-acknowledgements.plist @@ -0,0 +1,46 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2016 SwiftKick Mobile LLC + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + License + MIT + Title + SwiftMessages + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-dummy.m b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-dummy.m new file mode 100644 index 00000000..a9fef241 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_iMessageExtensionDemo : NSObject +@end +@implementation PodsDummy_Pods_iMessageExtensionDemo +@end diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-umbrella.h b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-umbrella.h new file mode 100644 index 00000000..b45e1cf3 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_iMessageExtensionDemoVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_iMessageExtensionDemoVersionString[]; + diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.debug.xcconfig b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.debug.xcconfig new file mode 100644 index 00000000..c23e4e35 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages/SwiftMessages.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "SwiftMessages" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.modulemap b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.modulemap new file mode 100644 index 00000000..ab391867 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.modulemap @@ -0,0 +1,6 @@ +framework module Pods_iMessageExtensionDemo { + umbrella header "Pods-iMessageExtensionDemo-umbrella.h" + + export * + module * { export * } +} diff --git a/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.release.xcconfig b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.release.xcconfig new file mode 100644 index 00000000..c23e4e35 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages/SwiftMessages.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "SwiftMessages" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages-SwiftMessages-Info.plist b/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages-SwiftMessages-Info.plist new file mode 100644 index 00000000..35c2f997 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages-SwiftMessages-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 9.0.1 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist b/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist new file mode 100644 index 00000000..35c2f997 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 9.0.1 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist new file mode 100644 index 00000000..2687f6bd --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 9.0.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-dummy.m b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-dummy.m new file mode 100644 index 00000000..dc460b82 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_SwiftMessages : NSObject +@end +@implementation PodsDummy_SwiftMessages +@end diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-prefix.pch b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-prefix.pch new file mode 100644 index 00000000..beb2a244 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-umbrella.h b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-umbrella.h new file mode 100644 index 00000000..9aa634f0 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double SwiftMessagesVersionNumber; +FOUNDATION_EXPORT const unsigned char SwiftMessagesVersionString[]; + diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.debug.xcconfig b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.debug.xcconfig new file mode 100644 index 00000000..9bbd3c8d --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.debug.xcconfig @@ -0,0 +1,15 @@ +APPLICATION_EXTENSION_API_ONLY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 SWIFTMESSAGES_APP_EXTENSIONS=1 +OTHER_LDFLAGS = $(inherited) -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFTMESSAGES_APP_EXTENSIONS +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.modulemap b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.modulemap new file mode 100644 index 00000000..96306d64 --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.modulemap @@ -0,0 +1,6 @@ +framework module SwiftMessages { + umbrella header "SwiftMessages-umbrella.h" + + export * + module * { export * } +} diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.release.xcconfig b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.release.xcconfig new file mode 100644 index 00000000..9bbd3c8d --- /dev/null +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages.release.xcconfig @@ -0,0 +1,15 @@ +APPLICATION_EXTENSION_API_ONLY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SwiftMessages +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 SWIFTMESSAGES_APP_EXTENSIONS=1 +OTHER_LDFLAGS = $(inherited) -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFTMESSAGES_APP_EXTENSIONS +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/iMessageDemo/iMessageDemo.xcodeproj/project.pbxproj b/iMessageDemo/iMessageDemo.xcodeproj/project.pbxproj index 05863d63..ff0e9049 100644 --- a/iMessageDemo/iMessageDemo.xcodeproj/project.pbxproj +++ b/iMessageDemo/iMessageDemo.xcodeproj/project.pbxproj @@ -13,9 +13,8 @@ 2272F21921080DD600AD190C /* iMessageExtensionDemo.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 2272F20A21080DD500AD190C /* iMessageExtensionDemo.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 2272F21F2108113F00AD190C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2272F21E2108113F00AD190C /* Main.storyboard */; }; 2272F221210811BE00AD190C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2272F220210811BE00AD190C /* LaunchScreen.storyboard */; }; - 22B96AF4213D94CC00357CB5 /* SwiftMessages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22FE3FE9211941FD0017303D /* SwiftMessages.framework */; }; - 22FE3FFD211944040017303D /* SwiftMessages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22FE3FE9211941FD0017303D /* SwiftMessages.framework */; }; - 22FE3FFE211944040017303D /* SwiftMessages.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 22FE3FE9211941FD0017303D /* SwiftMessages.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 76D3135B88AA54ECC98CBD36 /* Pods_iMessageDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73DC8D5C3B1552230D960BF7 /* Pods_iMessageDemo.framework */; }; + F49106CE51DB9708982AF779 /* Pods_iMessageExtensionDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E1E18BC615CEA5704F4B5FB /* Pods_iMessageExtensionDemo.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -26,34 +25,6 @@ remoteGlobalIDString = 2272F20921080DD500AD190C; remoteInfo = iMessageExtensionDemo; }; - 22FE3FE8211941FD0017303D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 22FE3FE2211941FD0017303D /* SwiftMessages.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 86B48AEC1D5A41C900063E2B; - remoteInfo = SwiftMessages; - }; - 22FE3FEC211941FD0017303D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 22FE3FE2211941FD0017303D /* SwiftMessages.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 86B48AF51D5A41C900063E2B; - remoteInfo = SwiftMessagesTests; - }; - 22FE3FFB211942A50017303D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 22FE3FE2211941FD0017303D /* SwiftMessages.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 86B48AEB1D5A41C900063E2B; - remoteInfo = SwiftMessages; - }; - 22FE3FFF211944040017303D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 22FE3FE2211941FD0017303D /* SwiftMessages.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 86B48AEB1D5A41C900063E2B; - remoteInfo = SwiftMessages; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -74,7 +45,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 22FE3FFE211944040017303D /* SwiftMessages.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -82,6 +52,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 212D588BA5EE4E8BF07B02D8 /* Pods-iMessageExtensionDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iMessageExtensionDemo.release.xcconfig"; path = "Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.release.xcconfig"; sourceTree = ""; }; + 21DDEA06F4193D7F35B70A53 /* Pods-iMessageDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iMessageDemo.release.xcconfig"; path = "Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.release.xcconfig"; sourceTree = ""; }; 2272F1F121080DAE00AD190C /* iMessageDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iMessageDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2272F1F421080DAE00AD190C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 2272F20021080DB200AD190C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -92,7 +64,10 @@ 2272F21621080DD600AD190C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2272F21E2108113F00AD190C /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 2272F220210811BE00AD190C /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - 22FE3FE2211941FD0017303D /* SwiftMessages.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftMessages.xcodeproj; path = ../SwiftMessages.xcodeproj; sourceTree = ""; }; + 4E1E18BC615CEA5704F4B5FB /* Pods_iMessageExtensionDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iMessageExtensionDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 73DC8D5C3B1552230D960BF7 /* Pods_iMessageDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iMessageDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 76B6E320915B554B5D628DFC /* Pods-iMessageDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iMessageDemo.debug.xcconfig"; path = "Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo.debug.xcconfig"; sourceTree = ""; }; + EE094075BD5252DAD69071F9 /* Pods-iMessageExtensionDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iMessageExtensionDemo.debug.xcconfig"; path = "Target Support Files/Pods-iMessageExtensionDemo/Pods-iMessageExtensionDemo.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -100,7 +75,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 22FE3FFD211944040017303D /* SwiftMessages.framework in Frameworks */, + 76D3135B88AA54ECC98CBD36 /* Pods_iMessageDemo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -108,7 +83,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 22B96AF4213D94CC00357CB5 /* SwiftMessages.framework in Frameworks */, + F49106CE51DB9708982AF779 /* Pods_iMessageExtensionDemo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -122,7 +97,7 @@ 2272F20E21080DD500AD190C /* iMessageExtensionDemo */, 2272F20B21080DD500AD190C /* Frameworks */, 2272F1F221080DAE00AD190C /* Products */, - 22FE3FE2211941FD0017303D /* SwiftMessages.xcodeproj */, + C99B3449FCA583CA3ECDC53C /* Pods */, ); sourceTree = ""; }; @@ -150,6 +125,8 @@ isa = PBXGroup; children = ( 2272F20C21080DD500AD190C /* Messages.framework */, + 73DC8D5C3B1552230D960BF7 /* Pods_iMessageDemo.framework */, + 4E1E18BC615CEA5704F4B5FB /* Pods_iMessageExtensionDemo.framework */, ); name = Frameworks; sourceTree = ""; @@ -164,13 +141,16 @@ path = iMessageExtensionDemo; sourceTree = ""; }; - 22FE3FE3211941FD0017303D /* Products */ = { + C99B3449FCA583CA3ECDC53C /* Pods */ = { isa = PBXGroup; children = ( - 22FE3FE9211941FD0017303D /* SwiftMessages.framework */, - 22FE3FED211941FD0017303D /* SwiftMessagesTests.xctest */, + 76B6E320915B554B5D628DFC /* Pods-iMessageDemo.debug.xcconfig */, + 21DDEA06F4193D7F35B70A53 /* Pods-iMessageDemo.release.xcconfig */, + EE094075BD5252DAD69071F9 /* Pods-iMessageExtensionDemo.debug.xcconfig */, + 212D588BA5EE4E8BF07B02D8 /* Pods-iMessageExtensionDemo.release.xcconfig */, ); - name = Products; + name = Pods; + path = Pods; sourceTree = ""; }; /* End PBXGroup section */ @@ -180,17 +160,18 @@ isa = PBXNativeTarget; buildConfigurationList = 2272F20321080DB200AD190C /* Build configuration list for PBXNativeTarget "iMessageDemo" */; buildPhases = ( + C9C10288A07806AC55B5E4B3 /* [CP] Check Pods Manifest.lock */, 2272F1ED21080DAE00AD190C /* Sources */, 2272F1EE21080DAE00AD190C /* Frameworks */, 2272F1EF21080DAE00AD190C /* Resources */, 2272F21D21080DD600AD190C /* Embed App Extensions */, 22FE4001211944040017303D /* Embed Frameworks */, + 77C3B4728FB9FC385B4279B6 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( 2272F21821080DD600AD190C /* PBXTargetDependency */, - 22FE4000211944040017303D /* PBXTargetDependency */, ); name = iMessageDemo; productName = iMessageDemo; @@ -201,6 +182,7 @@ isa = PBXNativeTarget; buildConfigurationList = 2272F21A21080DD600AD190C /* Build configuration list for PBXNativeTarget "iMessageExtensionDemo" */; buildPhases = ( + 7FD245EE0E3D4F436FEB306E /* [CP] Check Pods Manifest.lock */, 2272F20621080DD500AD190C /* Sources */, 2272F20721080DD500AD190C /* Frameworks */, 2272F20821080DD500AD190C /* Resources */, @@ -208,7 +190,6 @@ buildRules = ( ); dependencies = ( - 22FE3FFC211942A50017303D /* PBXTargetDependency */, ); name = iMessageExtensionDemo; productName = iMessageExtensionDemo; @@ -244,12 +225,6 @@ mainGroup = 2272F1E821080DAE00AD190C; productRefGroup = 2272F1F221080DAE00AD190C /* Products */; projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 22FE3FE3211941FD0017303D /* Products */; - ProjectRef = 22FE3FE2211941FD0017303D /* SwiftMessages.xcodeproj */; - }, - ); projectRoot = ""; targets = ( 2272F1F021080DAE00AD190C /* iMessageDemo */, @@ -258,23 +233,6 @@ }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - 22FE3FE9211941FD0017303D /* SwiftMessages.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SwiftMessages.framework; - remoteRef = 22FE3FE8211941FD0017303D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 22FE3FED211941FD0017303D /* SwiftMessagesTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = SwiftMessagesTests.xctest; - remoteRef = 22FE3FEC211941FD0017303D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXResourcesBuildPhase section */ 2272F1EF21080DAE00AD190C /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -295,6 +253,70 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 77C3B4728FB9FC385B4279B6 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iMessageDemo/Pods-iMessageDemo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 7FD245EE0E3D4F436FEB306E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-iMessageExtensionDemo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C9C10288A07806AC55B5E4B3 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-iMessageDemo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 2272F1ED21080DAE00AD190C /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -320,16 +342,6 @@ target = 2272F20921080DD500AD190C /* iMessageExtensionDemo */; targetProxy = 2272F21721080DD600AD190C /* PBXContainerItemProxy */; }; - 22FE3FFC211942A50017303D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = SwiftMessages; - targetProxy = 22FE3FFB211942A50017303D /* PBXContainerItemProxy */; - }; - 22FE4000211944040017303D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = SwiftMessages; - targetProxy = 22FE3FFF211944040017303D /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -460,6 +472,7 @@ }; 2272F20421080DB200AD190C /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 76B6E320915B554B5D628DFC /* Pods-iMessageDemo.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; @@ -478,6 +491,7 @@ }; 2272F20521080DB200AD190C /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 21DDEA06F4193D7F35B70A53 /* Pods-iMessageDemo.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; @@ -496,6 +510,7 @@ }; 2272F21B21080DD600AD190C /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = EE094075BD5252DAD69071F9 /* Pods-iMessageExtensionDemo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "iMessage App Icon"; CODE_SIGN_STYLE = Automatic; @@ -516,6 +531,7 @@ }; 2272F21C21080DD600AD190C /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 212D588BA5EE4E8BF07B02D8 /* Pods-iMessageExtensionDemo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "iMessage App Icon"; CODE_SIGN_STYLE = Automatic; diff --git a/iMessageDemo/iMessageDemo.xcworkspace/contents.xcworkspacedata b/iMessageDemo/iMessageDemo.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..d69114e3 --- /dev/null +++ b/iMessageDemo/iMessageDemo.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From b750f852e690ad3e81687b1a0b1a67c9e2d19653 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:30:45 -0500 Subject: [PATCH 090/139] Revert "refactor(MessageView): remove redundant words for `button` (#461)" This reverts commit c63e64e8a8988f0885e3ee23fb1e50f9b6cbd584. --- SwiftMessages/MessageView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages/MessageView.swift b/SwiftMessages/MessageView.swift index e844b074..d9be31d9 100644 --- a/SwiftMessages/MessageView.swift +++ b/SwiftMessages/MessageView.swift @@ -55,7 +55,7 @@ open class MessageView: BaseView, Identifiable, AccessibleMessage { /// An optional button. This buttons' `.TouchUpInside` event will automatically /// invoke the optional `buttonTapHandler`, but its fine to add other target - /// action handlers. + /// action handlers can be added. @IBOutlet open var button: UIButton? { didSet { if let old = oldValue { From 699e0cdc24098eb79081309e1c8560ede96a757c Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:30:59 -0500 Subject: [PATCH 091/139] Revert "Public Layout initializer" This reverts commit 4408c09c863b1c6af4d053fe17fd532a4f96b237. --- SwiftMessages/Layout.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift index 09c2c16f..83100822 100644 --- a/SwiftMessages/Layout.swift +++ b/SwiftMessages/Layout.swift @@ -24,8 +24,6 @@ public struct Layout { public var min = Layout() public var max = Layout() - public init() {} - public enum Boundary { case superview case safeArea From 6dd1a1c007daff122402e4de101f459429c5f8f3 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:31:09 -0500 Subject: [PATCH 092/139] Revert "Fix arg name" This reverts commit f3a0aca1111e891841e44227ec6a1d0d11b7de9d. --- SwiftMessages/Layout.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift index 83100822..0d02fa6c 100644 --- a/SwiftMessages/Layout.swift +++ b/SwiftMessages/Layout.swift @@ -35,7 +35,7 @@ public struct Layout { public enum Dimension { case absolute(CGFloat) case relative(CGFloat, to: Boundary) - case absoluteInsets(CGFloat, from: Boundary) + case absoluteInsets(CGFloat, to: Boundary) } public var width: Dimension? From c79f3b4133e11a7584176056e52771aa04ea0cd3 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:31:18 -0500 Subject: [PATCH 093/139] Revert "Add absoluteInsets size option" This reverts commit cc1b635513ebd9f350b41a172ec418dc3593494f. --- SwiftMessages/Layout.swift | 11 ----------- SwiftMessages/MaskingView.swift | 16 +++++----------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift index 0d02fa6c..4afcf7b7 100644 --- a/SwiftMessages/Layout.swift +++ b/SwiftMessages/Layout.swift @@ -35,7 +35,6 @@ public struct Layout { public enum Dimension { case absolute(CGFloat) case relative(CGFloat, to: Boundary) - case absoluteInsets(CGFloat, to: Boundary) } public var width: Dimension? @@ -82,16 +81,6 @@ extension Layout.Insets.Dimension { } } -extension Layout.Size.Dimension { - var boundary: Layout.Boundary? { - switch self { - case .absolute(_): return nil - case .relative(_, let boundary): return boundary - case .absoluteInsets(_, let boundary): return boundary - } - } -} - extension Layout.Center.Dimension { var boundary: Layout.Boundary { switch self { diff --git a/SwiftMessages/MaskingView.swift b/SwiftMessages/MaskingView.swift index 08c31d20..81301994 100644 --- a/SwiftMessages/MaskingView.swift +++ b/SwiftMessages/MaskingView.swift @@ -417,8 +417,10 @@ class MaskingView: PassthroughView, LayoutInstalling { for dimension: Layout.Size.Dimension, extractor: (CGRect) -> CGFloat ) -> CGFloat { - let insetBounds: CGRect = { - guard let boundary = dimension.boundary else { return .zero } + switch dimension { + case .absolute(let dimension): + return dimension + case .relative(let percentage, let boundary): let insets: UIEdgeInsets switch boundary { case .superview: insets = .zero @@ -430,15 +432,7 @@ class MaskingView: PassthroughView, LayoutInstalling { insets = layoutMargins } } - return bounds.inset(by: insets) - }() - switch dimension { - case .absolute(let dimension): - return dimension - case .relative(let percentage, _): - return extractor(insetBounds) * percentage - case .absoluteInsets(let dimension, _): - return extractor(insetBounds) - dimension * 2 + return extractor(bounds.inset(by: insets)) * percentage } } From 856f4da5e4c100d3b178cd9619587ddaad35dbe2 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:32:27 -0500 Subject: [PATCH 094/139] Revert "Adjust edge animation timing" This reverts commit e7d7e00c2d7f34bf0405c28e853564195bf369c3. # Conflicts: # SwiftMessages.xcodeproj/project.pbxproj --- SwiftMessages.xcodeproj/project.pbxproj | 10 ++++------ ...{EdgeAnimation.swift => TopBottomAnimation.swift} | 12 ++++++------ 2 files changed, 10 insertions(+), 12 deletions(-) rename SwiftMessages/{EdgeAnimation.swift => TopBottomAnimation.swift} (97%) diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index c9e779ae..9c9e8ee8 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -55,8 +55,7 @@ 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */; }; 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; - 2298C2091EE486E300E2DDC1 /* EdgeAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* EdgeAnimation.swift */; }; - 229F778125FAB1E9008C2ACB /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */; }; + 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; 22DFC9161EFF30F6001B1CA1 /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */; }; 22DFC9181F00674E001B1CA1 /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */; }; 22E01F641E74EC8B00ACE19A /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22E01F631E74EC8B00ACE19A /* MaskingView.swift */; }; @@ -144,8 +143,7 @@ 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILayoutPriority+Extensions.swift"; sourceTree = ""; }; 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; - 2298C2081EE486E300E2DDC1 /* EdgeAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EdgeAnimation.swift; sourceTree = ""; }; - 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Extensions.swift"; sourceTree = ""; }; + 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; 22A2EA6E24EC6CFA00BB2540 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CenteredView.xib; path = Resources/CenteredView.xib; sourceTree = ""; }; 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsPanHandler.swift; sourceTree = ""; }; @@ -224,7 +222,7 @@ 2244656C1EF1D62700C50413 /* Animations */ = { isa = PBXGroup; children = ( - 2298C2081EE486E300E2DDC1 /* EdgeAnimation.swift */, + 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */, 2270044A1FAFA6DD0045DDC3 /* PhysicsAnimation.swift */, 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */, ); @@ -560,7 +558,7 @@ 86BBA8FF1D5E040600FE8F16 /* Presenter.swift in Sources */, 86BBA9051D5E040C00FE8F16 /* Theme.swift in Sources */, 86BBA9081D5E040C00FE8F16 /* Error.swift in Sources */, - 2298C2091EE486E300E2DDC1 /* EdgeAnimation.swift in Sources */, + 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */, 86589D471D64B6E40041676C /* BaseView.swift in Sources */, 225304622290C76E00A03ACF /* NSLayoutConstraint+Extensions.swift in Sources */, 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */, diff --git a/SwiftMessages/EdgeAnimation.swift b/SwiftMessages/TopBottomAnimation.swift similarity index 97% rename from SwiftMessages/EdgeAnimation.swift rename to SwiftMessages/TopBottomAnimation.swift index 21039378..f8afc781 100644 --- a/SwiftMessages/EdgeAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -1,5 +1,5 @@ // -// EdgeAnimation.swift +// TopBottomAnimation.swift // SwiftMessages // // Created by Timothy Moose on 6/4/17. @@ -24,9 +24,9 @@ public class EdgeAnimation: NSObject, Animator { public let style: Style - open var showDuration: TimeInterval = 0.35 + open var showDuration: TimeInterval = 0.4 - open var hideDuration: TimeInterval = 0.25 + open var hideDuration: TimeInterval = 0.2 open var springDamping: CGFloat = 0.8 @@ -65,7 +65,7 @@ public class EdgeAnimation: NSObject, Animator { NotificationCenter.default.removeObserver(self) let view = context.messageView self.context = context - UIView.animate(withDuration: hideDuration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: [.beginFromCurrentState]) { + UIView.animate(withDuration: hideDuration, delay: 0, options: [.beginFromCurrentState, .curveEaseIn], animations: { switch self.style { case .top: view.transform = CGAffineTransform(translationX: 0, y: -view.frame.height) @@ -76,14 +76,14 @@ public class EdgeAnimation: NSObject, Animator { case .trailing: view.transform = CGAffineTransform(translationX: view.frame.maxX + view.frame.width, y: 0) } - } completion: { completed in + }, completion: { completed in #if SWIFTMESSAGES_APP_EXTENSIONS completion(completed) #else // Fix #131 by always completing if application isn't active. completion(completed || UIApplication.shared.applicationState != .active) #endif - } + }) } func install(context: AnimationContext) { From 0d7584e671f1ca72f6bae83349cfbb60633a0fa9 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:32:43 -0500 Subject: [PATCH 095/139] Revert "Expand scope of new sizing API" This reverts commit 3883abc3f4918aaea605a8f7450c81675a9ebf65. --- Demo/Demo/Base.lproj/Main.storyboard | 398 ++++++------------ Demo/Demo/ViewControllersViewController.swift | 78 +--- SwiftMessages.xcodeproj/project.pbxproj | 12 +- SwiftMessages/Animator.swift | 4 +- SwiftMessages/BaseView.swift | 109 ++--- SwiftMessages/CornerRoundingView.swift | 4 +- SwiftMessages/Layout.swift | 91 ---- SwiftMessages/MaskingView.swift | 307 +++----------- SwiftMessages/MessageSizeable.swift | 65 +++ SwiftMessages/MessageSizing.swift | 13 + SwiftMessages/PhysicsAnimation.swift | 37 +- SwiftMessages/Presenter.swift | 4 +- SwiftMessages/SwiftMessagesSegue.swift | 210 ++++----- SwiftMessages/TopBottomAnimation.swift | 133 ++---- .../UILayoutPriority+Extensions.swift | 18 +- .../UIViewController+Extensions.swift | 6 +- 16 files changed, 470 insertions(+), 1019 deletions(-) delete mode 100644 SwiftMessages/Layout.swift create mode 100644 SwiftMessages/MessageSizeable.swift create mode 100644 SwiftMessages/MessageSizing.swift diff --git a/Demo/Demo/Base.lproj/Main.storyboard b/Demo/Demo/Base.lproj/Main.storyboard index f8968f69..08ab75d2 100644 --- a/Demo/Demo/Base.lproj/Main.storyboard +++ b/Demo/Demo/Base.lproj/Main.storyboard @@ -1,9 +1,8 @@ - + - - + @@ -31,7 +30,7 @@ - + @@ -48,7 +47,7 @@ @@ -82,7 +81,7 @@ @@ -117,7 +116,7 @@ @@ -152,7 +151,7 @@ @@ -186,7 +185,7 @@ @@ -224,7 +223,7 @@ - + @@ -642,7 +641,7 @@ @@ -656,7 +655,7 @@ @@ -675,7 +674,7 @@ @@ -689,7 +688,7 @@ @@ -811,255 +810,115 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - + - - - - + + + + @@ -1072,7 +931,7 @@ - + @@ -1092,7 +951,7 @@ - + @@ -1190,19 +1049,18 @@ - + - @@ -1226,17 +1084,11 @@ - - - - - - - - - - + + + + diff --git a/Demo/Demo/ViewControllersViewController.swift b/Demo/Demo/ViewControllersViewController.swift index 733dc07d..f3339ebc 100644 --- a/Demo/Demo/ViewControllersViewController.swift +++ b/Demo/Demo/ViewControllersViewController.swift @@ -19,31 +19,6 @@ class SwiftMessagesTopSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .topMessage) - messageView.layout.size.height = .absolute(300) - } -} - -class SwiftMessagesBottomSegue: SwiftMessagesSegue { - override public init(identifier: String?, source: UIViewController, destination: UIViewController) { - super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .bottomMessage) - messageView.layout.size.height = .absolute(300) - } -} - -class SwiftMessagesLeadingSegue: SwiftMessagesSegue { - override public init(identifier: String?, source: UIViewController, destination: UIViewController) { - super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .leadingMessage) - messageView.layout.size.width = .absolute(300) - } -} - -class SwiftMessagesTrailingSegue: SwiftMessagesSegue { - override public init(identifier: String?, source: UIViewController, destination: UIViewController) { - super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .trailingMessage) - messageView.layout.size.width = .absolute(300) } } @@ -51,31 +26,6 @@ class SwiftMessagesTopCardSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .topCard) - messageView.layout.size.height = .absolute(300) - } -} - -class SwiftMessagesBottomCardSegue: SwiftMessagesSegue { - override public init(identifier: String?, source: UIViewController, destination: UIViewController) { - super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .bottomCard) - messageView.layout.size.height = .absolute(300) - } -} - -class SwiftMessagesLeadingCardSegue: SwiftMessagesSegue { - override public init(identifier: String?, source: UIViewController, destination: UIViewController) { - super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .leadingCard) - messageView.layout.size.width = .absolute(300) - } -} - -class SwiftMessagesTrailingCardSegue: SwiftMessagesSegue { - override public init(identifier: String?, source: UIViewController, destination: UIViewController) { - super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .trailingCard) - messageView.layout.size.width = .absolute(300) } } @@ -83,31 +33,28 @@ class SwiftMessagesTopTabSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .topTab) - messageView.layout.size.height = .absolute(300) } } -class SwiftMessagesBottomTabSegue: SwiftMessagesSegue { +class SwiftMessagesBottomSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .bottomTab) - messageView.layout.size.height = .absolute(300) + configure(layout: .bottomMessage) } } -class SwiftMessagesLeadingTabSegue: SwiftMessagesSegue { +class SwiftMessagesBottomCardSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .leadingTab) - messageView.layout.size.width = .absolute(300) + configure(layout: .bottomCard) + messageView.messageSize.width = .relative(0.75, from: .superview) } } -class SwiftMessagesTrailingTabSegue: SwiftMessagesSegue { +class SwiftMessagesBottomTabSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .trailingTab) - messageView.layout.size.width = .absolute(300) + configure(layout: .bottomTab) } } @@ -115,16 +62,5 @@ class SwiftMessagesCenteredSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .centered) - messageView.layout.size.height = .absolute(300) - } -} - -class SwiftMessagesOffCenteredSegue: SwiftMessagesSegue { - override public init(identifier: String?, source: UIViewController, destination: UIViewController) { - super.init(identifier: identifier, source: source, destination: destination) - configure(layout: .centered) - messageView.layout.insets.top = .absolute(0, from: .safeArea) - messageView.layout.center.x = .relative(0.33, in: .safeArea) - messageView.layout.size.height = .absolute(300) } } diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 9c9e8ee8..823f37b4 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -51,7 +51,8 @@ 228DF5681FAD0806004F8A39 /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */; }; 228DF5691FAD0806004F8A39 /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5481FAD0805004F8A39 /* successIconLight.png */; }; 228DF56A1FAD0806004F8A39 /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */; }; - 2290944825D88A05002E8111 /* Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290944725D88A05002E8111 /* Layout.swift */; }; + 2290944825D88A05002E8111 /* MessageSizeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290944725D88A05002E8111 /* MessageSizeable.swift */; }; + 2290957825D9BC9F002E8111 /* MessageSizing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290957725D9BC9F002E8111 /* MessageSizing.swift */; }; 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */; }; 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; @@ -139,7 +140,8 @@ 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = infoIconSubtle.png; path = Resources/infoIconSubtle.png; sourceTree = ""; }; 228DF5481FAD0805004F8A39 /* successIconLight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = successIconLight.png; path = Resources/successIconLight.png; sourceTree = ""; }; 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; - 2290944725D88A05002E8111 /* Layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Layout.swift; sourceTree = ""; }; + 2290944725D88A05002E8111 /* MessageSizeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSizeable.swift; sourceTree = ""; }; + 2290957725D9BC9F002E8111 /* MessageSizing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSizing.swift; sourceTree = ""; }; 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILayoutPriority+Extensions.swift"; sourceTree = ""; }; 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; @@ -300,7 +302,8 @@ 8644955C1D4FAF7C0056EB2A /* WindowViewController.swift */, 867BED201D622793005212E3 /* BackgroundViewable.swift */, 864495551D4F7C390056EB2A /* Identifiable.swift */, - 2290944725D88A05002E8111 /* Layout.swift */, + 2290944725D88A05002E8111 /* MessageSizeable.swift */, + 2290957725D9BC9F002E8111 /* MessageSizing.swift */, 86AAF81D1D5549680031EE32 /* MarginAdjustable.swift */, 22E307FE1E74C5B100E35893 /* AccessibleMessage.swift */, 86AAF82A1D580DD70031EE32 /* Error.swift */, @@ -537,7 +540,7 @@ 86BBA8FC1D5E03F100FE8F16 /* MessageView.swift in Sources */, 86BBA9061D5E040C00FE8F16 /* Identifiable.swift in Sources */, 22F27951210CE25900273E7F /* CornerRoundingView.swift in Sources */, - 2290944825D88A05002E8111 /* Layout.swift in Sources */, + 2290944825D88A05002E8111 /* MessageSizeable.swift in Sources */, 86BBA9011D5E040600FE8F16 /* PassthroughWindow.swift in Sources */, 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */, 86BBA9031D5E040600FE8F16 /* UIViewController+Extensions.swift in Sources */, @@ -561,6 +564,7 @@ 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */, 86589D471D64B6E40041676C /* BaseView.swift in Sources */, 225304622290C76E00A03ACF /* NSLayoutConstraint+Extensions.swift in Sources */, + 2290957825D9BC9F002E8111 /* MessageSizing.swift in Sources */, 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */, 867BED211D622793005212E3 /* BackgroundViewable.swift in Sources */, 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */, diff --git a/SwiftMessages/Animator.swift b/SwiftMessages/Animator.swift index 3897dd1f..29a4552f 100644 --- a/SwiftMessages/Animator.swift +++ b/SwiftMessages/Animator.swift @@ -45,13 +45,13 @@ public struct SafeZoneConflicts: OptionSet { public class AnimationContext { public let messageView: UIView - public let containerView: UIView & LayoutInstalling + public let containerView: UIView & MessageSizing public let safeZoneConflicts: SafeZoneConflicts public let interactiveHide: Bool internal init( messageView: UIView, - containerView: UIView & LayoutInstalling, + containerView: UIView & MessageSizing, safeZoneConflicts: SafeZoneConflicts, interactiveHide: Bool ) { diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index cdde9008..2ae86a45 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -14,7 +14,7 @@ import UIKit of the optional SwiftMessages protocols and provides some convenience functions and a configurable tap handler. Message views do not need to inherit from `BaseVew`. */ -open class BaseView: UIView, BackgroundViewable, MarginAdjustable, LayoutDefining { +open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeable { /* MARK: - IB outlets @@ -63,7 +63,6 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, LayoutDefinin */ /** - TODO SIZE - update documentation A convenience function for installing a content view as a subview of `backgroundView` and pinning the edges to `backgroundView` with the specified `insets`. @@ -83,7 +82,6 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, LayoutDefinin } /** - TODO SIZE - update documentation - insets removed A convenience function for installing a background view and pinning to the layout margins. This is useful for creating programatic layouts where the background view needs to be inset from the message view's edges (like a card-style layout). @@ -92,7 +90,7 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, LayoutDefinin assigned to the `backgroundView` property. - Parameter insets: The amount to inset the content view from the margins. Default is zero inset. */ - open func installBackgroundView(_ backgroundView: UIView) { + open func installBackgroundView(_ backgroundView: UIView, insets: UIEdgeInsets = UIEdgeInsets.zero) { backgroundView.translatesAutoresizingMaskIntoConstraints = false if backgroundView != self { backgroundView.removeFromSuperview() @@ -102,56 +100,64 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, LayoutDefinin NSLayoutConstraint.activate([ backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) .with(priority: .belowMessageSizeable), - backgroundView.topAnchor.constraint(equalTo: topAnchor) - .with(priority: .belowMessageSizeable), - backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor) - .with(priority: .belowMessageSizeable), + backgroundView.topAnchor.constraint( + equalTo: layoutMarginsGuide.topAnchor, + constant: insets.top + ).with(priority: .belowMessageSizeable), + backgroundView.bottomAnchor.constraint( + equalTo: layoutMarginsGuide.bottomAnchor, + constant: -insets.bottom + ).with(priority: .belowMessageSizeable), backgroundView.heightAnchor.constraint(equalToConstant: 350) .with(priority: UILayoutPriority(rawValue: 200)), - backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor) - .with(priority: .belowMessageSizeable), - backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor) - .with(priority: .belowMessageSizeable), + backgroundView.leftAnchor.constraint( + equalTo: layoutMarginsGuide.leftAnchor, + constant: insets.left + ).with(priority: .belowMessageSizeable), + backgroundView.rightAnchor.constraint( + equalTo: layoutMarginsGuide.rightAnchor, + constant: -insets.right + ).with(priority: .belowMessageSizeable), ]) installTapRecognizer() } -// /** -// A convenience function for installing a background view and pinning to the horizontal -// layout margins and to the vertical edges. This is useful for creating programatic layouts where -// the background view needs to be inset from the message view's horizontal edges (like a tab-style layout). -// -// - Parameter backgroundView: The view to be installed as a subview and -// assigned to the `backgroundView` property. -// - Parameter insets: The amount to inset the content view from the horizontal margins and vertical edges. -// Default is zero inset. -// */ -// open func installBackgroundVerticalView(_ backgroundView: UIView, insets: UIEdgeInsets = UIEdgeInsets.zero) { -// backgroundView.translatesAutoresizingMaskIntoConstraints = false -// if backgroundView != self { -// backgroundView.removeFromSuperview() -// } -// addSubview(backgroundView) -// self.backgroundView = backgroundView -// NSLayoutConstraint.activate([ -// backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) -// .with(priority: .belowMessageSizeable), -// backgroundView.topAnchor.constraint(equalTo: topAnchor, constant: insets.top) -// .with(priority: .required), -// backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -insets.bottom) -// .with(priority: .required), -// backgroundView.heightAnchor.constraint(equalToConstant: 350) -// .with(priority: UILayoutPriority(rawValue: 200)), -// backgroundView.leftAnchor.constraint( -// equalTo: layoutMarginsGuide.leftAnchor, constant: insets.left -// ).with(priority: .belowMessageSizeable), -// backgroundView.rightAnchor.constraint( -// equalTo: layoutMarginsGuide.rightAnchor, -// constant: -insets.right -// ).with(priority: .belowMessageSizeable), -// ]) -// installTapRecognizer() -// } + /** + A convenience function for installing a background view and pinning to the horizontal + layout margins and to the vertical edges. This is useful for creating programatic layouts where + the background view needs to be inset from the message view's horizontal edges (like a tab-style layout). + + - Parameter backgroundView: The view to be installed as a subview and + assigned to the `backgroundView` property. + - Parameter insets: The amount to inset the content view from the horizontal margins and vertical edges. + Default is zero inset. + */ + open func installBackgroundVerticalView(_ backgroundView: UIView, insets: UIEdgeInsets = UIEdgeInsets.zero) { + backgroundView.translatesAutoresizingMaskIntoConstraints = false + if backgroundView != self { + backgroundView.removeFromSuperview() + } + addSubview(backgroundView) + self.backgroundView = backgroundView + NSLayoutConstraint.activate([ + backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) + .with(priority: .belowMessageSizeable), + backgroundView.topAnchor.constraint(equalTo: topAnchor, constant: insets.top) + .with(priority: .required), + backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -insets.bottom) + .with(priority: .required), + backgroundView.heightAnchor.constraint(equalToConstant: 350) + .with(priority: UILayoutPriority(rawValue: 200)), + backgroundView.leftAnchor.constraint( + equalTo: layoutMarginsGuide.leftAnchor, constant: insets.left + ).with(priority: .belowMessageSizeable), + backgroundView.rightAnchor.constraint( + equalTo: layoutMarginsGuide.rightAnchor, + constant: -insets.right + ).with(priority: .belowMessageSizeable), + ]) + installTapRecognizer() + } /* MARK: - Tap handler @@ -197,8 +203,11 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, LayoutDefinin // MARK: - MessageSizeable - /// Configure the view's layout - public var layout = Layout() + /// Configure the view's size + public var messageSize = MessageSize() + + /// Configure the view's insets from the container + public var messageInsets = MessageInsets() /* MARK: - MarginAdjustable diff --git a/SwiftMessages/CornerRoundingView.swift b/SwiftMessages/CornerRoundingView.swift index 7db484fb..398b731c 100644 --- a/SwiftMessages/CornerRoundingView.swift +++ b/SwiftMessages/CornerRoundingView.swift @@ -24,12 +24,12 @@ open class CornerRoundingView: UIView { /// rounded. For example, the layout in TabView.xib rounds the bottom corners /// when displayed from the top and the top corners when displayed from the bottom. /// When this property is `true`, the `roundedCorners` property will be overwritten - /// by relevant animators (e.g. `EdgeAnimation`). + /// by relevant animators (e.g. `TopBottomAnimation`). @IBInspectable open var roundsLeadingCorners: Bool = false /// Specifies which corners should be rounded. When `roundsLeadingCorners = true`, relevant - /// relevant animators (e.g. `EdgeAnimation`) will overwrite the value of this property. + /// relevant animators (e.g. `TopBottomAnimation`) will overwrite the value of this property. open var roundedCorners: UIRectCorner = [.allCorners] { didSet { updateMaskPath() diff --git a/SwiftMessages/Layout.swift b/SwiftMessages/Layout.swift deleted file mode 100644 index 4afcf7b7..00000000 --- a/SwiftMessages/Layout.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// BoundaryInsets.swift -// SwiftMessages -// -// Created by Timothy Moose on 2/13/21. -// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. -// - -import UIKit - -public protocol LayoutDefining { - var layout: Layout { get } -} - -public protocol LayoutInstalling { - func install(layoutDefiningView: LayoutDefining & UIView) -} - -public struct Layout { - - public var size = Size() - public var insets = Insets() - public var center = Center() - public var min = Layout() - public var max = Layout() - - public enum Boundary { - case superview - case safeArea - case margin - } - - public struct Size { - - public enum Dimension { - case absolute(CGFloat) - case relative(CGFloat, to: Boundary) - } - - public var width: Dimension? - public var height: Dimension? - } - - public struct Insets { - - public enum Dimension { - case absolute(CGFloat, from: Boundary) - case relative(CGFloat, from: Boundary) - } - - public var top: Dimension? - public var bottom: Dimension? - public var leading: Dimension? - public var trailing: Dimension? - } - - public struct Center { - - public enum Dimension { - case absolute(CGFloat, in: Boundary) - case relative(CGFloat, in: Boundary) - } - - public var x: Dimension? - public var y: Dimension? - } - - public struct Layout { - public var size = Size() - public var insets = Insets() - public var center = Center() - } -} - -extension Layout.Insets.Dimension { - var boundary: Layout.Boundary { - switch self { - case .absolute(_, let boundary): return boundary - case .relative(_, let boundary): return boundary - } - } -} - -extension Layout.Center.Dimension { - var boundary: Layout.Boundary { - switch self { - case .absolute(_, let boundary): return boundary - case .relative(_, let boundary): return boundary - } - } -} diff --git a/SwiftMessages/MaskingView.swift b/SwiftMessages/MaskingView.swift index 81301994..889ac9de 100644 --- a/SwiftMessages/MaskingView.swift +++ b/SwiftMessages/MaskingView.swift @@ -24,13 +24,13 @@ import UIKit // .with(priority: UILayoutPriority(rawValue: 200)), // ] -class MaskingView: PassthroughView, LayoutInstalling { +class MaskingView: PassthroughView, MessageSizing { - func install(layoutDefiningView: UIView & LayoutDefining) { - self.layoutDefiningView?.removeFromSuperview() - self.layoutDefiningView = layoutDefiningView - layoutDefiningView.translatesAutoresizingMaskIntoConstraints = false - addSubview(layoutDefiningView) + func install(sizeableView: MessageSizeable & UIView) { + self.sizeableView?.removeFromSuperview() + self.sizeableView = sizeableView + sizeableView.translatesAutoresizingMaskIntoConstraints = false + addSubview(sizeableView) setNeedsUpdateConstraints() } @@ -96,7 +96,7 @@ class MaskingView: PassthroughView, LayoutInstalling { private var keyboardTrackingView: KeyboardTrackingView? private var cachedConstraints: [NSLayoutConstraint] = [] private let messageInsetsGuide = UILayoutGuide() - private var layoutDefiningView: (LayoutDefining & UIView)? + private var sizeableView: (MessageSizeable & UIView)? override func addSubview(_ view: UIView) { super.addSubview(view) @@ -110,35 +110,20 @@ class MaskingView: PassthroughView, LayoutInstalling { super.updateConstraints() NSLayoutConstraint.deactivate(cachedConstraints) cachedConstraints = [] - if let layoutDefiningView = layoutDefiningView { - let layout = layoutDefiningView.layout - add(insets: layout.insets, relation: .equal) - add(insets: layout.min.insets, relation: .min) - add(insets: layout.max.insets, relation: .max) - add(layoutDefiningView: layoutDefiningView) - } + if let top = sizeableView?.messageInsets.top { update(top: top) } + if let bottom = sizeableView?.messageInsets.bottom { update(bottom: bottom) } + if let leading = sizeableView?.messageInsets.leading { update(leading: leading) } + if let trailing = sizeableView?.messageInsets.trailing { update(trailing: trailing) } + if let sizeableView = sizeableView { update(sizeableView: sizeableView) } NSLayoutConstraint.activate(cachedConstraints) } - private enum ConstraintRelation { - case equal - case min - case max - } - - private func add(insets: Layout.Insets, relation: ConstraintRelation) { - if let top = insets.top { add(top: top, relation: relation) } - if let bottom = insets.bottom { add(bottom: bottom, relation: relation) } - if let leading = insets.leading { add(leading: leading, relation: relation) } - if let trailing = insets.trailing { add(trailing: trailing, relation: relation) } - } - - private func add(top: Layout.Insets.Dimension, relation: ConstraintRelation) { + private func update(top: MessageInsets.Dimension) { let length: CGFloat switch top { - case .absolute(let dimension, _): + case .absoluteMargin(let dimension, _): length = dimension - case .relative(let percentage, _): + case .relativeMargin(let percentage, _): length = bounds.height * percentage } let otherAnchor: NSLayoutYAxisAnchor @@ -152,20 +137,18 @@ class MaskingView: PassthroughView, LayoutInstalling { otherAnchor = layoutMarginsGuide.topAnchor } } - add( - anchor: messageInsetsGuide.topAnchor, - otherAnchor: otherAnchor, - constant: length, - relation: relation + cachedConstraints.append( + messageInsetsGuide.topAnchor.constraint(equalTo: otherAnchor, constant: length) + .with(priority: .messageInset) ) } - private func add(bottom: Layout.Insets.Dimension, relation: ConstraintRelation) { + private func update(bottom: MessageInsets.Dimension) { let length: CGFloat switch bottom { - case .absolute(let dimension, _): + case .absoluteMargin(let dimension, _): length = dimension - case .relative(let percentage, _): + case .relativeMargin(let percentage, _): length = bounds.height * percentage } let otherAnchor: NSLayoutYAxisAnchor @@ -179,20 +162,18 @@ class MaskingView: PassthroughView, LayoutInstalling { otherAnchor = layoutMarginsGuide.bottomAnchor } } - add( - anchor: otherAnchor, - otherAnchor: messageInsetsGuide.bottomAnchor, - constant: length, - relation: relation + cachedConstraints.append( + messageInsetsGuide.bottomAnchor.constraint(equalTo: otherAnchor, constant: -length) + .with(priority: .messageInset) ) } - private func add(leading: Layout.Insets.Dimension, relation: ConstraintRelation) { + private func update(leading: MessageInsets.Dimension) { let length: CGFloat switch leading { - case .absolute(let dimension, _): + case .absoluteMargin(let dimension, _): length = dimension - case .relative(let percentage, _): + case .relativeMargin(let percentage, _): length = bounds.width * percentage } let otherAnchor: NSLayoutXAxisAnchor @@ -206,20 +187,18 @@ class MaskingView: PassthroughView, LayoutInstalling { otherAnchor = layoutMarginsGuide.leadingAnchor } } - add( - anchor: messageInsetsGuide.leadingAnchor, - otherAnchor: otherAnchor, - constant: length, - relation: relation + cachedConstraints.append( + messageInsetsGuide.leadingAnchor.constraint(equalTo: otherAnchor, constant: length) + .with(priority: .messageInset) ) } - private func add(trailing: Layout.Insets.Dimension, relation: ConstraintRelation) { + private func update(trailing: MessageInsets.Dimension) { let length: CGFloat switch trailing { - case .absolute(let dimension, _): + case .absoluteMargin(let dimension, _): length = dimension - case .relative(let percentage, _): + case .relativeMargin(let percentage, _): length = bounds.width * percentage } let otherAnchor: NSLayoutXAxisAnchor @@ -233,193 +212,55 @@ class MaskingView: PassthroughView, LayoutInstalling { otherAnchor = layoutMarginsGuide.trailingAnchor } } - add( - anchor: otherAnchor, - otherAnchor: messageInsetsGuide.trailingAnchor, - constant: length, - relation: relation + cachedConstraints.append( + messageInsetsGuide.trailingAnchor.constraint(equalTo: otherAnchor, constant: -length) + .with(priority: .messageInset) ) } - private func add( - anchor: NSLayoutXAxisAnchor, - otherAnchor: NSLayoutXAxisAnchor, - constant: CGFloat, - relation: ConstraintRelation - ) { - let constraint: NSLayoutConstraint - switch relation { - case .equal: - constraint = anchor - .constraint(equalTo: otherAnchor, constant: constant) - .with(priority: .messageInsets) - case .min: - constraint = anchor - .constraint(greaterThanOrEqualTo: otherAnchor, constant: constant) - .with(priority: .messageInsetsBounds) - case .max: - constraint = anchor - .constraint(lessThanOrEqualTo: otherAnchor, constant: constant) - .with(priority: .messageInsetsBounds) - } - cachedConstraints.append(constraint) - } - - private func add( - anchor: NSLayoutYAxisAnchor, - otherAnchor: NSLayoutYAxisAnchor, - constant: CGFloat, - relation: ConstraintRelation - ) { - let constraint: NSLayoutConstraint - switch relation { - case .equal: - constraint = anchor - .constraint(equalTo: otherAnchor, constant: constant) - .with(priority: .messageInsets) - case .min: - constraint = anchor - .constraint(greaterThanOrEqualTo: otherAnchor, constant: constant) - .with(priority: .messageInsetsBounds) - case .max: - constraint = anchor - .constraint(lessThanOrEqualTo: otherAnchor, constant: constant) - .with(priority: .messageInsetsBounds) - } - cachedConstraints.append(constraint) - } - - private func add(layoutDefiningView view: LayoutDefining & UIView) { + private func update(sizeableView view: MessageSizeable & UIView) { cachedConstraints += [ messageInsetsGuide.topAnchor.constraint(equalTo: view.topAnchor), messageInsetsGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor), messageInsetsGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor), messageInsetsGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor), ] - add(layoutDefiningView: view, size: view.layout.size, relation: .equal) - add(layoutDefiningView: view, size: view.layout.min.size, relation: .min) - add(layoutDefiningView: view, size: view.layout.max.size, relation: .max) - add(layoutDefiningView: view, center: view.layout.center, relation: .equal) - add(layoutDefiningView: view, center: view.layout.min.center, relation: .min) - add(layoutDefiningView: view, center: view.layout.max.center, relation: .max) - } - - private func add( - layoutDefiningView view: LayoutDefining & UIView, - size: Layout.Size, - relation: ConstraintRelation - ) { - if let width = size.width { - let length = self.length(for: width) { $0.width } - let constraint: NSLayoutConstraint - switch relation { - case .equal: - constraint = view.widthAnchor.constraint(equalToConstant: length) + if let width = view.messageSize.width { + let length = self.length(for: width, extractor: { $0.width }) + cachedConstraints.append( + view.widthAnchor.constraint(equalToConstant: length) .with(priority: .messageSize) - case .min: - constraint = view.widthAnchor.constraint(greaterThanOrEqualToConstant: length) - .with(priority: .messageSizeBounds) - case .max: - constraint = view.widthAnchor.constraint(lessThanOrEqualToConstant: length) - .with(priority: .messageSizeBounds) - } - cachedConstraints.append(constraint) + ) } - if let height = size.height { - let length = self.length(for: height) { $0.height } - let constraint: NSLayoutConstraint - switch relation { - case .equal: - constraint = view.heightAnchor.constraint(equalToConstant: length) + if let height = view.messageSize.height { + let length = self.length(for: height, extractor: { $0.height }) + cachedConstraints.append( + view.heightAnchor.constraint(equalToConstant: length) .with(priority: .messageSize) - case .min: - constraint = view.heightAnchor.constraint(greaterThanOrEqualToConstant: length) - .with(priority: .messageSizeBounds) - case .max: - constraint = view.heightAnchor.constraint(lessThanOrEqualToConstant: length) - .with(priority: .messageSizeBounds) - } - cachedConstraints.append(constraint) - } - } - - - private func add( - layoutDefiningView view: LayoutDefining & UIView, - center: Layout.Center, - relation: ConstraintRelation - ) { - if let x = center.x { - let length = self.length(for: x) { ($0.minX, $0.maxX) } - let otherAnchor: NSLayoutXAxisAnchor - switch x.boundary { - case .superview: otherAnchor = leadingAnchor - case .margin: otherAnchor = layoutMarginsGuide.leadingAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = safeAreaLayoutGuide.leadingAnchor - } else { - otherAnchor = layoutMarginsGuide.leadingAnchor - } - } - let constraint: NSLayoutConstraint - switch relation { - case .equal: - constraint = view.centerXAnchor.constraint(equalTo: otherAnchor, constant: length) - .with(priority: .messageCenter) - case .min: - constraint = view.centerXAnchor.constraint( - greaterThanOrEqualTo: otherAnchor, - constant: length - ).with(priority: .messageSizeBounds) - case .max: - constraint = view.centerXAnchor.constraint( - lessThanOrEqualTo: otherAnchor, - constant: length - ).with(priority: .messageSizeBounds) - } - cachedConstraints.append(constraint) - } - if let y = center.y { - let length = self.length(for: y) { ($0.minY, $0.maxY) } - let otherAnchor: NSLayoutYAxisAnchor - switch y.boundary { - case .superview: otherAnchor = topAnchor - case .margin: otherAnchor = layoutMarginsGuide.topAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = safeAreaLayoutGuide.topAnchor - } else { - otherAnchor = layoutMarginsGuide.topAnchor - } - } - let constraint: NSLayoutConstraint - switch relation { - case .equal: - constraint = view.centerYAnchor.constraint(equalTo: otherAnchor, constant: length) - .with(priority: .messageCenter) - case .min: - constraint = view.centerYAnchor.constraint( - greaterThanOrEqualTo: otherAnchor, - constant: length - ).with(priority: .messageSizeBounds) - case .max: - constraint = view.centerYAnchor.constraint( - lessThanOrEqualTo: otherAnchor, - constant: length - ).with(priority: .messageSizeBounds) - } - cachedConstraints.append(constraint) + ) } } private func length( - for dimension: Layout.Size.Dimension, + for dimension: MessageSize.Dimension, extractor: (CGRect) -> CGFloat ) -> CGFloat { switch dimension { case .absolute(let dimension): return dimension + case .absoluteMargin(let margin, let boundary): + let insets: UIEdgeInsets + switch boundary { + case .superview: insets = .zero + case .margin: insets = layoutMargins + case .safeArea: + if #available(iOS 11.0, *) { + insets = safeAreaInsets + } else { + insets = layoutMargins + } + } + return extractor(bounds.inset(by: insets)) - margin * 2 case .relative(let percentage, let boundary): let insets: UIEdgeInsets switch boundary { @@ -435,30 +276,4 @@ class MaskingView: PassthroughView, LayoutInstalling { return extractor(bounds.inset(by: insets)) * percentage } } - - private func length( - for dimension: Layout.Center.Dimension, - extractor: (CGRect) -> (CGFloat, CGFloat) - ) -> CGFloat { - let insets: UIEdgeInsets - switch dimension.boundary { - case .superview: insets = .zero - case .margin: insets = layoutMargins - case .safeArea: - if #available(iOS 11.0, *) { - insets = safeAreaInsets - } else { - insets = layoutMargins - } - } - let insetBounds = bounds.inset(by: insets) - switch dimension { - case .absolute(let dimension, _): - let (min, _) = extractor(insetBounds) - return min + dimension - case .relative(let percentage, _): - let (min, max) = extractor(insetBounds) - return min + (max - min) * percentage - } - } } diff --git a/SwiftMessages/MessageSizeable.swift b/SwiftMessages/MessageSizeable.swift new file mode 100644 index 00000000..662f1839 --- /dev/null +++ b/SwiftMessages/MessageSizeable.swift @@ -0,0 +1,65 @@ +// +// BoundaryInsets.swift +// SwiftMessages +// +// Created by Timothy Moose on 2/13/21. +// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. +// + +import UIKit + +public protocol MessageSizeable { + var messageSize: MessageSize { get } + var messageInsets: MessageInsets { get } +} + +public enum MessageBoundary { + case superview + case safeArea + case margin +} + +/// Insets used for specifying view sizing options in terms of insets from the containing superview or safe area. +public struct MessageInsets { + + public enum Dimension { + + /// Dimension should maintain an absolute margin to the given container boundary. + case absoluteMargin(CGFloat, from: MessageBoundary) + + /// Dimension should maintain a relative margin to the given container boundary. + case relativeMargin(CGFloat, from: MessageBoundary) + } + + public var top: Dimension? + public var bottom: Dimension? + public var leading: Dimension? + public var trailing: Dimension? +} + +public struct MessageSize { + + public enum Dimension { + + /// Dimensions should be an absolute length + case absolute(CGFloat) + + /// Dimension should maintain an absolute length to the given container boundary. + case absoluteMargin(CGFloat, from: MessageBoundary) + + /// Dimension should maintain a relative margin to the given boundary. + case relative(CGFloat, from: MessageBoundary) + } + + public var width: Dimension? + public var height: Dimension? +} + +extension MessageInsets.Dimension { + var boundary: MessageBoundary { + switch self { + case .absoluteMargin(_, let boundary): return boundary + case .relativeMargin(_, let boundary): return boundary + } + } +} diff --git a/SwiftMessages/MessageSizing.swift b/SwiftMessages/MessageSizing.swift new file mode 100644 index 00000000..b4c47dd3 --- /dev/null +++ b/SwiftMessages/MessageSizing.swift @@ -0,0 +1,13 @@ +// +// MessageSizing.swift +// SwiftMessages +// +// Created by Timothy Moose on 2/14/21. +// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. +// + +import Foundation + +public protocol MessageSizing { + func install(sizeableView: MessageSizeable & UIView) +} diff --git a/SwiftMessages/PhysicsAnimation.swift b/SwiftMessages/PhysicsAnimation.swift index 46f3d1ef..0fb976c5 100644 --- a/SwiftMessages/PhysicsAnimation.swift +++ b/SwiftMessages/PhysicsAnimation.swift @@ -70,41 +70,18 @@ public class PhysicsAnimation: NSObject, Animator { messageView = view containerView = container self.context = context - if let layoutDefiningView = view as? LayoutDefining & UIView { - container.install(layoutDefiningView: layoutDefiningView) - } else { - view.translatesAutoresizingMaskIntoConstraints = false - container.addSubview(view) - } + view.translatesAutoresizingMaskIntoConstraints = false + container.addSubview(view) switch placement { case .center: - view.centerYAnchor.constraint(equalTo: container.centerYAnchor) - .with(priority: UILayoutPriority(200)).isActive = true + view.centerYAnchor.constraint(equalTo: container.centerYAnchor).with(priority: UILayoutPriority(200)).isActive = true case .top: - view.topAnchor.constraint(equalTo: container.topAnchor) - .with(priority: UILayoutPriority(200)).isActive = true + view.topAnchor.constraint(equalTo: container.topAnchor).with(priority: UILayoutPriority(200)).isActive = true case .bottom: - view.bottomAnchor.constraint(equalTo: container.bottomAnchor) - .with(priority: UILayoutPriority(200)).isActive = true + view.bottomAnchor.constraint(equalTo: container.bottomAnchor).with(priority: UILayoutPriority(200)).isActive = true } - NSLayoutConstraint( - item: view, - attribute: .leading, - relatedBy: .equal, - toItem: container, - attribute: .leading, - multiplier: 1, - constant: 0 - ).with(priority: .belowMessageSizeable).isActive = true - NSLayoutConstraint( - item: view, - attribute: .trailing, - relatedBy: .equal, - toItem: container, - attribute: .trailing, - multiplier: 1, - constant: 0 - ).with(priority: .belowMessageSizeable).isActive = true + NSLayoutConstraint(item: view, attribute: .leading, relatedBy: .equal, toItem: container, attribute: .leading, multiplier: 1, constant: 0).isActive = true + NSLayoutConstraint(item: view, attribute: .trailing, relatedBy: .equal, toItem: container, attribute: .trailing, multiplier: 1, constant: 0).isActive = true // Important to layout now in order to get the right safe area insets container.layoutIfNeeded() adjustMargins() diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index 1ba7aa68..11243f54 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -105,9 +105,9 @@ class Presenter: NSObject { private static func animator(forPresentationStyle style: SwiftMessages.PresentationStyle, delegate: AnimationDelegate) -> Animator { switch style { case .top: - return EdgeAnimation(style: .top, delegate: delegate) + return TopBottomAnimation(style: .top, delegate: delegate) case .bottom: - return EdgeAnimation(style: .bottom, delegate: delegate) + return TopBottomAnimation(style: .bottom, delegate: delegate) case .center: return PhysicsAnimation(delegate: delegate) case .custom(let animator): diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index 8013ccd0..f20491bc 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -69,50 +69,60 @@ import UIKit open class SwiftMessagesSegue: UIStoryboardSegue { /** - Specifies one of the pre-defined layout configurations. + Specifies one of the pre-defined layouts, mirroring a subset of `MessageView.Layout`. */ public enum Layout { - /// The standard message view layout that slides down from the top edge. + /// The standard message view layout on top. case topMessage - /// The standard message view layout that slides up from the bottom edge. + /// The standard message view layout on bottom. case bottomMessage - /// The standard message view layout that slides in from the leading edge. - case leadingMessage - - /// The standard message view layout that slides in from the trailing edge. - case trailingMessage - - /// A floating card-style view with rounded corners that slides down from the top edge. + /// A floating card-style view with rounded corners on top case topCard - /// A floating card-style view with rounded corners that slides up from the bottom edge. - case bottomCard - - /// A floating card-style view with rounded corners that slides in from the leading edge. - case leadingCard - - /// A floating card-style view with rounded corners that slides in from the trailing edge. - case trailingCard - - /// A floating tab-style view with rounded leading corners that slides down from the top edge. + /// A floating tab-style view with rounded corners on bottom case topTab - /// A floating tab-style view with rounded leading corners that slides up from the bottom edge. - case bottomTab - - /// A floating tab-style view with rounded leading corners that slides in from the leading edge. - case leadingTab + /// A floating card-style view with rounded corners on bottom + case bottomCard - /// A floating tab-style view with rounded leading corners that slides in from the traling edge. - case trailingTab + /// A floating tab-style view with rounded corners on top + case bottomTab /// A floating card-style view typically used with `.center` presentation style. case centered } + /** + Specifies how the view controller's view is installed into the + containing message view. + */ + public enum Containment { + + /** + The view controller's view is installed for edge-to-edge display, extending into the safe areas + to the device edges. This is done by calling `messageView.installContentView(:insets:)` + See that method's documentation for additional details. + */ + case content + + /** + The view controller's view is installed for card-style layouts, inset from the margins + and avoiding safe areas. This is done by calling `messageView.installBackgroundView(:insets:)`. + See that method's documentation for details. + */ + case background + + /** + The view controller's view is installed for tab-style layouts, inset from the side margins, but extending + to the device edge on the top or bottom. This is done by calling `messageView.installBackgroundVerticalView(:insets:)`. + See that method's documentation for details. + */ + case backgroundVertical + } + /// The presentation style to use. See the SwiftMessages.PresentationStyle for details. public var presentationStyle: SwiftMessages.PresentationStyle { get { return messenger.defaultConfig.presentationStyle } @@ -164,11 +174,17 @@ open class SwiftMessagesSegue: UIStoryboardSegue { /** The view controller's view is embedded in `containerView` before being installed into - `messageView`. This view provides configurable continuous rounded corners (see the parent + `messageView`. This view provides configurable squircle (round) corners (see the parent class `CornerRoundingView`). */ public var containerView: CornerRoundingView = CornerRoundingView() + /** + Specifies how the view controller's view is installed into the + containing message view. See `Containment` for details. + */ + public var containment: Containment = .content + /** Supply an instance of `KeyboardTrackingView` to have the message view avoid the keyboard. */ @@ -212,130 +228,57 @@ extension SwiftMessagesSegue { /// A convenience method for configuring some pre-defined layouts that mirror a subset of `MessageView.Layout`. public func configure(layout: Layout) { messageView.bounceAnimationOffset = 0 + containment = .content containerView.cornerRadius = 0 containerView.roundsLeadingCorners = false messageView.configureDropShadow() switch layout { case .topMessage: -// TODO SIZE are these layout margin settings still relevant? -// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) -// messageView.collapseLayoutMarginAdditions = false - let animation = EdgeAnimation(style: .top) + messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) + messageView.collapseLayoutMarginAdditions = false + let animation = TopBottomAnimation(style: .top) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .bottomMessage: -// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) -// messageView.collapseLayoutMarginAdditions = false - let animation = EdgeAnimation(style: .bottom) - animation.springDamping = 1 - presentationStyle = .custom(animator: animation) - case .leadingMessage: -// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) -// messageView.collapseLayoutMarginAdditions = false - let animation = EdgeAnimation(style: .leading) - animation.springDamping = 1 - presentationStyle = .custom(animator: animation) - case .trailingMessage: -// messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) -// messageView.collapseLayoutMarginAdditions = false - let animation = EdgeAnimation(style: .trailing) + messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) + messageView.collapseLayoutMarginAdditions = false + let animation = TopBottomAnimation(style: .bottom) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .topCard: - messageView.layout.insets.top = .absolute(0, from: .safeArea) - messageView.layout.insets.leading = .absolute(0, from: .safeArea) - messageView.layout.insets.trailing = .absolute(0, from: .safeArea) - messageView.layout.min.insets.top = .absolute(10, from: .superview) - messageView.layout.min.insets.leading = .absolute(10, from: .superview) - messageView.layout.min.insets.trailing = .absolute(10, from: .superview) - messageView.layout.min.insets.bottom = .absolute(10, from: .safeArea) + containment = .background + messageView.layoutMarginAdditions = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) + messageView.collapseLayoutMarginAdditions = true containerView.cornerRadius = 15 presentationStyle = .top case .bottomCard: - messageView.layout.insets.bottom = .absolute(0, from: .safeArea) - messageView.layout.insets.leading = .absolute(0, from: .safeArea) - messageView.layout.insets.trailing = .absolute(0, from: .safeArea) - messageView.layout.min.insets.bottom = .absolute(10, from: .superview) - messageView.layout.min.insets.leading = .absolute(10, from: .superview) - messageView.layout.min.insets.trailing = .absolute(10, from: .superview) - messageView.layout.min.insets.top = .absolute(10, from: .safeArea) + containment = .background + messageView.layoutMarginAdditions = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) + messageView.collapseLayoutMarginAdditions = true containerView.cornerRadius = 15 presentationStyle = .bottom - case .leadingCard: - messageView.layout.insets.leading = .absolute(0, from: .safeArea) - messageView.layout.insets.top = .absolute(0, from: .safeArea) - messageView.layout.insets.bottom = .absolute(0, from: .safeArea) - messageView.layout.min.insets.leading = .absolute(10, from: .superview) - messageView.layout.min.insets.top = .absolute(10, from: .superview) - messageView.layout.min.insets.bottom = .absolute(10, from: .superview) - messageView.layout.min.insets.trailing = .absolute(10, from: .safeArea) - containerView.cornerRadius = 15 - let animation = EdgeAnimation(style: .leading) - presentationStyle = .custom(animator: animation) - case .trailingCard: - messageView.layout.insets.trailing = .absolute(0, from: .safeArea) - messageView.layout.insets.top = .absolute(0, from: .safeArea) - messageView.layout.insets.bottom = .absolute(0, from: .safeArea) - messageView.layout.min.insets.trailing = .absolute(10, from: .superview) - messageView.layout.min.insets.top = .absolute(10, from: .superview) - messageView.layout.min.insets.bottom = .absolute(10, from: .superview) - messageView.layout.min.insets.leading = .absolute(10, from: .safeArea) - containerView.cornerRadius = 15 - let animation = EdgeAnimation(style: .trailing) - presentationStyle = .custom(animator: animation) case .topTab: - messageView.layout.insets.top = .absolute(0, from: .superview) - messageView.layout.insets.leading = .absolute(0, from: .safeArea) - messageView.layout.insets.trailing = .absolute(0, from: .safeArea) - messageView.layout.min.insets.leading = .absolute(10, from: .superview) - messageView.layout.min.insets.trailing = .absolute(10, from: .superview) - messageView.layout.min.insets.bottom = .absolute(10, from: .safeArea) + containment = .backgroundVertical + messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 10, bottom: 20, right: 10) + messageView.collapseLayoutMarginAdditions = true containerView.cornerRadius = 15 containerView.roundsLeadingCorners = true - let animation = EdgeAnimation(style: .top) + let animation = TopBottomAnimation(style: .top) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .bottomTab: - messageView.layout.insets.bottom = .absolute(0, from: .superview) - messageView.layout.insets.leading = .absolute(0, from: .safeArea) - messageView.layout.insets.trailing = .absolute(0, from: .safeArea) - messageView.layout.min.insets.leading = .absolute(10, from: .superview) - messageView.layout.min.insets.trailing = .absolute(10, from: .superview) - messageView.layout.min.insets.top = .absolute(10, from: .safeArea) + containment = .backgroundVertical + messageView.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 10, bottom: 20, right: 10) + messageView.collapseLayoutMarginAdditions = true containerView.cornerRadius = 15 containerView.roundsLeadingCorners = true - let animation = EdgeAnimation(style: .bottom) - animation.springDamping = 1 - presentationStyle = .custom(animator: animation) - case .leadingTab: - messageView.layout.insets.leading = .absolute(0, from: .superview) - messageView.layout.insets.top = .absolute(0, from: .safeArea) - messageView.layout.insets.bottom = .absolute(0, from: .safeArea) - messageView.layout.min.insets.top = .absolute(10, from: .superview) - messageView.layout.min.insets.bottom = .absolute(10, from: .superview) - messageView.layout.min.insets.trailing = .absolute(10, from: .safeArea) - containerView.cornerRadius = 15 - containerView.roundsLeadingCorners = true - let animation = EdgeAnimation(style: .leading) - animation.springDamping = 1 - presentationStyle = .custom(animator: animation) - case .trailingTab: - messageView.layout.insets.trailing = .absolute(0, from: .superview) - messageView.layout.insets.top = .absolute(0, from: .safeArea) - messageView.layout.insets.bottom = .absolute(0, from: .safeArea) - messageView.layout.min.insets.top = .absolute(10, from: .superview) - messageView.layout.min.insets.bottom = .absolute(10, from: .superview) - messageView.layout.min.insets.leading = .absolute(10, from: .safeArea) - containerView.cornerRadius = 15 - containerView.roundsLeadingCorners = true - let animation = EdgeAnimation(style: .trailing) + let animation = TopBottomAnimation(style: .bottom) animation.springDamping = 1 presentationStyle = .custom(animator: animation) case .centered: - messageView.layout.min.insets.top = .absolute(10, from: .safeArea) - messageView.layout.min.insets.bottom = .absolute(10, from: .safeArea) - messageView.layout.min.insets.leading = .absolute(10, from: .safeArea) - messageView.layout.min.insets.trailing = .absolute(10, from: .safeArea) + containment = .background + messageView.layoutMarginAdditions = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) + messageView.collapseLayoutMarginAdditions = true containerView.cornerRadius = 15 presentationStyle = .center } @@ -400,12 +343,21 @@ extension SwiftMessagesSegue { } completeTransition = transitionContext.completeTransition let transitionContainer = transitionContext.containerView - // Install the background and content views - do { + toView.translatesAutoresizingMaskIntoConstraints = false + segue.containerView.addSubview(toView) + segue.containerView.topAnchor.constraint(equalTo: toView.topAnchor).isActive = true + segue.containerView.bottomAnchor.constraint(equalTo: toView.bottomAnchor).isActive = true + segue.containerView.leadingAnchor.constraint(equalTo: toView.leadingAnchor).isActive = true + segue.containerView.trailingAnchor.constraint(equalTo: toView.trailingAnchor).isActive = true + // Install the `toView` into the message view. + switch segue.containment { + case .content: + segue.messageView.installContentView(segue.containerView) + case .background: segue.messageView.installBackgroundView(segue.containerView) - segue.messageView.installContentView(toView) + case .backgroundVertical: + segue.messageView.installBackgroundVerticalView(segue.containerView) } - let toVC = transitionContext.viewController(forKey: .to) // Nav controller automatically includes height of nav bar in, diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index f8afc781..0a91fc3f 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -8,22 +8,19 @@ import UIKit -@available(*, deprecated, message: "Class renamed to `EdgeAnimation` to reflect new ability to do leading and trailing animations.") -public typealias TopBottomAnimation = EdgeAnimation - -public class EdgeAnimation: NSObject, Animator { +public class TopBottomAnimation: NSObject, Animator { public enum Style { case top case bottom - case leading - case trailing } public weak var delegate: AnimationDelegate? public let style: Style + open var heightDimension: Dimension? + open var showDuration: TimeInterval = 0.4 open var hideDuration: TimeInterval = 0.2 @@ -71,10 +68,6 @@ public class EdgeAnimation: NSObject, Animator { view.transform = CGAffineTransform(translationX: 0, y: -view.frame.height) case .bottom: view.transform = CGAffineTransform(translationX: 0, y: view.frame.maxY + view.frame.height) - case .leading: // TODO SIZE do proper leading and trailing - view.transform = CGAffineTransform(translationX: -view.frame.width, y: 0) - case .trailing: - view.transform = CGAffineTransform(translationX: view.frame.maxX + view.frame.width, y: 0) } }, completion: { completed in #if SWIFTMESSAGES_APP_EXTENSIONS @@ -95,66 +88,41 @@ public class EdgeAnimation: NSObject, Animator { if let adjustable = context.messageView as? MarginAdjustable { bounceOffset = adjustable.bounceAnimationOffset } - if let layoutDefiningView = view as? LayoutDefining & UIView { - container.install(layoutDefiningView: layoutDefiningView) + if let sizeableView = view as? MessageSizeable & UIView { + container.install(sizeableView: sizeableView) } else { view.translatesAutoresizingMaskIntoConstraints = false container.addSubview(view) } // Horizontal constraints do { + view.leadingAnchor.constraint(equalTo: container.leadingAnchor) + .with(priority: .belowMessageSizeable - 1) + .isActive = true + view.centerXAnchor.constraint(equalTo: container.centerXAnchor) + .with(priority: .belowMessageSizeable) + .isActive = true } switch style { case .top: - NSLayoutConstraint.activate([ - view.leadingAnchor.constraint(equalTo: container.leadingAnchor) - .with(priority: .belowMessageSizeable - 1), - view.centerXAnchor.constraint(equalTo: container.centerXAnchor) - .with(priority: .belowMessageSizeable), - view.topAnchor.constraint(equalTo: container.topAnchor, constant: -bounceOffset) - .with(priority: .belowMessageSizeable) - ]) + view.topAnchor.constraint(equalTo: container.topAnchor, constant: -bounceOffset) + .with(priority: .belowMessageSizeable) + .isActive = true case .bottom: - NSLayoutConstraint.activate([ - view.leadingAnchor.constraint(equalTo: container.leadingAnchor) - .with(priority: .belowMessageSizeable - 1), - view.centerXAnchor.constraint(equalTo: container.centerXAnchor) - .with(priority: .belowMessageSizeable), - view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: bounceOffset) - .with(priority: .belowMessageSizeable) - ]) - case .leading: - NSLayoutConstraint.activate([ - view.topAnchor.constraint(equalTo: container.topAnchor) - .with(priority: .belowMessageSizeable - 1), - view.centerYAnchor.constraint(equalTo: container.centerYAnchor) - .with(priority: .belowMessageSizeable), - view.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: -bounceOffset) - .with(priority: .belowMessageSizeable) - ]) - case .trailing: - NSLayoutConstraint.activate([ - view.topAnchor.constraint(equalTo: container.topAnchor) - .with(priority: .belowMessageSizeable - 1), - view.centerYAnchor.constraint(equalTo: container.centerYAnchor) - .with(priority: .belowMessageSizeable), - view.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: bounceOffset) - .with(priority: .belowMessageSizeable) - ]) + view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: bounceOffset) + .with(priority: .belowMessageSizeable) + .isActive = true } // Important to layout now in order to get the right safe area insets container.layoutIfNeeded() adjustMargins() container.layoutIfNeeded() + let animationDistance = view.frame.height switch style { case .top: - view.transform = CGAffineTransform(translationX: 0, y: -view.frame.height) + view.transform = CGAffineTransform(translationX: 0, y: -animationDistance) case .bottom: - view.transform = CGAffineTransform(translationX: 0, y: view.frame.height) - case .leading: - view.transform = CGAffineTransform(translationX: -view.frame.width, y: 0) - case .trailing: - view.transform = CGAffineTransform(translationX: view.frame.width, y: 0) + view.transform = CGAffineTransform(translationX: 0, y: animationDistance) } if context.interactiveHide { if let view = view as? BackgroundViewable { @@ -171,10 +139,6 @@ public class EdgeAnimation: NSObject, Animator { cornerRoundingView.roundedCorners = [.bottomLeft, .bottomRight] case .bottom: cornerRoundingView.roundedCorners = [.topLeft, .topRight] - case .leading: - cornerRoundingView.roundedCorners = [.topRight, .bottomRight] - case .trailing: - cornerRoundingView.roundedCorners = [.topLeft, .bottomLeft] } } } @@ -192,10 +156,6 @@ public class EdgeAnimation: NSObject, Animator { layoutMargins.top += bounceOffset case .bottom: layoutMargins.bottom += bounceOffset - case .leading: - layoutMargins.left += bounceOffset - case .trailing: - layoutMargins.right += bounceOffset } adjustable.layoutMargins = layoutMargins } @@ -231,39 +191,21 @@ public class EdgeAnimation: NSObject, Animator { fileprivate var rubberBanding = false fileprivate var closeSpeed: CGFloat = 0.0 fileprivate var closePercent: CGFloat = 0.0 - fileprivate var panTranslation: CGFloat = 0.0 + fileprivate var panTranslationY: CGFloat = 0.0 @objc func pan(_ pan: UIPanGestureRecognizer) { switch pan.state { case .changed: guard let view = messageView else { return } - let length: CGFloat - switch style { - case .top, .bottom: - length = view.bounds.height - bounceOffset - case .leading, .trailing: - length = view.bounds.width - bounceOffset - } - if length <= 0 { return } + let height = view.bounds.height - bounceOffset + if height <= 0 { return } var velocity = pan.velocity(in: view) var translation = pan.translation(in: view) - switch style { - case .top: + if case .top = style { velocity.y *= -1.0 translation.y *= -1.0 - case .leading: - velocity.x *= -1.0 - translation.x *= -1.0 - case .bottom, .trailing: - break - } - var translationAmount: CGFloat - switch style { - case .top, .bottom: - translationAmount = translation.y >= 0 ? translation.y : -pow(abs(translation.y), 0.7) - case .leading, .trailing: - translationAmount = translation.x >= 0 ? translation.x : -pow(abs(translation.x), 0.7) } + var translationAmount = translation.y >= 0 ? translation.y : -pow(abs(translation.y), 0.7) if !closing { // Turn on rubber banding if background view is inset from message view. if let background = (messageView as? BackgroundViewable)?.backgroundView, background != view { @@ -272,10 +214,6 @@ public class EdgeAnimation: NSObject, Animator { rubberBanding = background.frame.minY > 0 case .bottom: rubberBanding = background.frame.maxY < view.bounds.height - case .leading: - rubberBanding = background.frame.minX > 0 - case .trailing: - rubberBanding = background.frame.maxX < view.bounds.width } } if !rubberBanding && translationAmount < 0 { return } @@ -288,30 +226,19 @@ public class EdgeAnimation: NSObject, Animator { view.transform = CGAffineTransform(translationX: 0, y: -translationAmount) case .bottom: view.transform = CGAffineTransform(translationX: 0, y: translationAmount) - case .leading: - view.transform = CGAffineTransform(translationX: -translationAmount, y: 0) - case .trailing: - view.transform = CGAffineTransform(translationX: translationAmount, y: 0) - } - switch style { - case .top, .bottom: - closeSpeed = velocity.y - closePercent = translation.y / length - panTranslation = translation.y - case .leading, .trailing: - closeSpeed = velocity.x - closePercent = translation.x / length - panTranslation = translation.x } + closeSpeed = velocity.y + closePercent = translation.y / height + panTranslationY = translation.y case .ended, .cancelled: - if closeSpeed > closeSpeedThreshold || closePercent > closePercentThreshold || panTranslation > closeAbsoluteThreshold { + if closeSpeed > closeSpeedThreshold || closePercent > closePercentThreshold || panTranslationY > closeAbsoluteThreshold { delegate?.hide(animator: self) } else { closing = false rubberBanding = false closeSpeed = 0.0 closePercent = 0.0 - panTranslation = 0.0 + panTranslationY = 0.0 showAnimation(completion: { (completed) in self.delegate?.panEnded(animator: self) }) diff --git a/SwiftMessages/UILayoutPriority+Extensions.swift b/SwiftMessages/UILayoutPriority+Extensions.swift index ae6dc07e..1fd3ab88 100644 --- a/SwiftMessages/UILayoutPriority+Extensions.swift +++ b/SwiftMessages/UILayoutPriority+Extensions.swift @@ -9,18 +9,10 @@ import UIKit /// The priority used for `MessageSizeable` constraints -extension UILayoutPriority { - /// A constraint priority higher than those used for `MessageSizeable` - public static let aboveMessageSizeable: UILayoutPriority = messageInsetsBounds + 1 - - /// A constraint priority lower than those used for `MessageSizeable` - public static let belowMessageSizeable: UILayoutPriority = messageCenter - 1 - - static let messageCenter: UILayoutPriority = UILayoutPriority(900) - static let messageSize: UILayoutPriority = UILayoutPriority(901) - static let messageInsets: UILayoutPriority = UILayoutPriority(902) - static let messageCenterBounds: UILayoutPriority = UILayoutPriority(903) - static let messageSizeBounds: UILayoutPriority = UILayoutPriority(904) - static let messageInsetsBounds: UILayoutPriority = UILayoutPriority(905) +public extension UILayoutPriority { + static let aboveMessageSizeable: UILayoutPriority = messageInset + 1 + static let belowMessageSizeable: UILayoutPriority = messageSize - 1 + static let messageSize: UILayoutPriority = UILayoutPriority(900) + static let messageInset: UILayoutPriority = UILayoutPriority(901) } diff --git a/SwiftMessages/UIViewController+Extensions.swift b/SwiftMessages/UIViewController+Extensions.swift index 6cedc0d5..7fbd4dd1 100644 --- a/SwiftMessages/UIViewController+Extensions.swift +++ b/SwiftMessages/UIViewController+Extensions.swift @@ -87,14 +87,14 @@ extension UIViewController { } extension SwiftMessages.PresentationStyle { - /// A temporary workaround to allow custom presentation contexts using `EdgeAnimation` + /// A temporary workaround to allow custom presentation contexts using `TopBottomAnimation` /// to display properly behind bars. THe long term solution is to refactor all of the /// presentation context logic to work with safe area insets. - var topBottomStyle: EdgeAnimation.Style? { + var topBottomStyle: TopBottomAnimation.Style? { switch self { case .top: return .top case .bottom: return .bottom - case .custom(let animator): return (animator as? EdgeAnimation)?.style + case .custom(let animator): return (animator as? TopBottomAnimation)?.style case .center: return nil } } From 616353c33a8d2a0ce241b3f1b4f43e9172328059 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:33:13 -0500 Subject: [PATCH 096/139] Revert "Add sizing options" This reverts commit 5b5973b5249a7228fc798ebe72f983a27517adb4. # Conflicts: # SwiftMessages.xcodeproj/project.pbxproj --- Demo/Demo/ViewControllersViewController.swift | 1 - SwiftMessages.xcodeproj/project.pbxproj | 17 +- SwiftMessages/Animator.swift | 4 +- SwiftMessages/BaseView.swift | 107 +++++---- SwiftMessages/BoundaryInsets.swift | 41 ++++ SwiftMessages/MaskingView.swift | 213 +----------------- SwiftMessages/MessageSizeable.swift | 65 ------ SwiftMessages/MessageSizing.swift | 13 -- SwiftMessages/Resources/CardView.xib | 25 +- SwiftMessages/Resources/CenteredView.xib | 27 ++- SwiftMessages/Resources/TabView.xib | 25 +- SwiftMessages/SwiftMessagesSegue.swift | 8 +- SwiftMessages/TopBottomAnimation.swift | 104 +++++++-- .../UILayoutPriority+Extensions.swift | 18 -- 14 files changed, 263 insertions(+), 405 deletions(-) create mode 100644 SwiftMessages/BoundaryInsets.swift delete mode 100644 SwiftMessages/MessageSizeable.swift delete mode 100644 SwiftMessages/MessageSizing.swift delete mode 100644 SwiftMessages/UILayoutPriority+Extensions.swift diff --git a/Demo/Demo/ViewControllersViewController.swift b/Demo/Demo/ViewControllersViewController.swift index f3339ebc..6fb14eeb 100644 --- a/Demo/Demo/ViewControllersViewController.swift +++ b/Demo/Demo/ViewControllersViewController.swift @@ -47,7 +47,6 @@ class SwiftMessagesBottomCardSegue: SwiftMessagesSegue { override public init(identifier: String?, source: UIViewController, destination: UIViewController) { super.init(identifier: identifier, source: source, destination: destination) configure(layout: .bottomCard) - messageView.messageSize.width = .relative(0.75, from: .superview) } } diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 823f37b4..f5296fde 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -51,9 +51,7 @@ 228DF5681FAD0806004F8A39 /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */; }; 228DF5691FAD0806004F8A39 /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5481FAD0805004F8A39 /* successIconLight.png */; }; 228DF56A1FAD0806004F8A39 /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */; }; - 2290944825D88A05002E8111 /* MessageSizeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290944725D88A05002E8111 /* MessageSizeable.swift */; }; - 2290957825D9BC9F002E8111 /* MessageSizing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290957725D9BC9F002E8111 /* MessageSizing.swift */; }; - 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */; }; + 2290944825D88A05002E8111 /* BoundaryInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290944725D88A05002E8111 /* BoundaryInsets.swift */; }; 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; @@ -140,9 +138,7 @@ 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = infoIconSubtle.png; path = Resources/infoIconSubtle.png; sourceTree = ""; }; 228DF5481FAD0805004F8A39 /* successIconLight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = successIconLight.png; path = Resources/successIconLight.png; sourceTree = ""; }; 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; - 2290944725D88A05002E8111 /* MessageSizeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSizeable.swift; sourceTree = ""; }; - 2290957725D9BC9F002E8111 /* MessageSizing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSizing.swift; sourceTree = ""; }; - 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILayoutPriority+Extensions.swift"; sourceTree = ""; }; + 2290944725D88A05002E8111 /* BoundaryInsets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoundaryInsets.swift; sourceTree = ""; }; 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; @@ -215,8 +211,6 @@ children = ( 220655111FAF82B600F4E00F /* MarginAdjustable+Extensions.swift */, 22774B9F20B5EF2A00813732 /* UIEdgeInsets+Extensions.swift */, - 2290958025D9D407002E8111 /* UILayoutPriority+Extensions.swift */, - 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */, ); name = Extensions; sourceTree = ""; @@ -302,12 +296,11 @@ 8644955C1D4FAF7C0056EB2A /* WindowViewController.swift */, 867BED201D622793005212E3 /* BackgroundViewable.swift */, 864495551D4F7C390056EB2A /* Identifiable.swift */, - 2290944725D88A05002E8111 /* MessageSizeable.swift */, - 2290957725D9BC9F002E8111 /* MessageSizing.swift */, 86AAF81D1D5549680031EE32 /* MarginAdjustable.swift */, 22E307FE1E74C5B100E35893 /* AccessibleMessage.swift */, 86AAF82A1D580DD70031EE32 /* Error.swift */, 2298C2061EE480D000E2DDC1 /* Animator.swift */, + 2290944725D88A05002E8111 /* BoundaryInsets.swift */, 2298C2041EE47DC900E2DDC1 /* Weak.swift */, 22F27950210CE25900273E7F /* CornerRoundingView.swift */, 225304652293000C00A03ACF /* KeyboardTrackingView.swift */, @@ -540,7 +533,7 @@ 86BBA8FC1D5E03F100FE8F16 /* MessageView.swift in Sources */, 86BBA9061D5E040C00FE8F16 /* Identifiable.swift in Sources */, 22F27951210CE25900273E7F /* CornerRoundingView.swift in Sources */, - 2290944825D88A05002E8111 /* MessageSizeable.swift in Sources */, + 2290944825D88A05002E8111 /* BoundaryInsets.swift in Sources */, 86BBA9011D5E040600FE8F16 /* PassthroughWindow.swift in Sources */, 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */, 86BBA9031D5E040600FE8F16 /* UIViewController+Extensions.swift in Sources */, @@ -564,10 +557,8 @@ 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */, 86589D471D64B6E40041676C /* BaseView.swift in Sources */, 225304622290C76E00A03ACF /* NSLayoutConstraint+Extensions.swift in Sources */, - 2290957825D9BC9F002E8111 /* MessageSizing.swift in Sources */, 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */, 867BED211D622793005212E3 /* BackgroundViewable.swift in Sources */, - 2290958125D9D407002E8111 /* UILayoutPriority+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SwiftMessages/Animator.swift b/SwiftMessages/Animator.swift index 29a4552f..b95bcaf9 100644 --- a/SwiftMessages/Animator.swift +++ b/SwiftMessages/Animator.swift @@ -45,13 +45,13 @@ public struct SafeZoneConflicts: OptionSet { public class AnimationContext { public let messageView: UIView - public let containerView: UIView & MessageSizing + public let containerView: UIView public let safeZoneConflicts: SafeZoneConflicts public let interactiveHide: Bool internal init( messageView: UIView, - containerView: UIView & MessageSizing, + containerView: UIView, safeZoneConflicts: SafeZoneConflicts, interactiveHide: Bool ) { diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index 2ae86a45..93c9df96 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -14,7 +14,7 @@ import UIKit of the optional SwiftMessages protocols and provides some convenience functions and a configurable tap handler. Message views do not need to inherit from `BaseVew`. */ -open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeable { +open class BaseView: UIView, BackgroundViewable, MarginAdjustable, HasBoundaryInsets { /* MARK: - IB outlets @@ -97,28 +97,20 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab } addSubview(backgroundView) self.backgroundView = backgroundView - NSLayoutConstraint.activate([ - backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) - .with(priority: .belowMessageSizeable), - backgroundView.topAnchor.constraint( - equalTo: layoutMarginsGuide.topAnchor, - constant: insets.top - ).with(priority: .belowMessageSizeable), - backgroundView.bottomAnchor.constraint( - equalTo: layoutMarginsGuide.bottomAnchor, - constant: -insets.bottom - ).with(priority: .belowMessageSizeable), - backgroundView.heightAnchor.constraint(equalToConstant: 350) - .with(priority: UILayoutPriority(rawValue: 200)), - backgroundView.leftAnchor.constraint( - equalTo: layoutMarginsGuide.leftAnchor, - constant: insets.left - ).with(priority: .belowMessageSizeable), - backgroundView.rightAnchor.constraint( - equalTo: layoutMarginsGuide.rightAnchor, - constant: -insets.right - ).with(priority: .belowMessageSizeable), - ]) + backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor).with(priority: UILayoutPriority(rawValue: 950)).isActive = true + backgroundView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor, constant: insets.top).with(priority: UILayoutPriority(rawValue: 900)).isActive = true + backgroundView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor, constant: -insets.bottom).with(priority: UILayoutPriority(rawValue: 900)).isActive = true + backgroundView.heightAnchor.constraint(equalToConstant: 350).with(priority: UILayoutPriority(rawValue: 200)).isActive = true + layoutConstraints = [ + backgroundView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor, constant: insets.left).with(priority: UILayoutPriority(rawValue: 900)), + backgroundView.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor, constant: -insets.right).with(priority: UILayoutPriority(rawValue: 900)), + ] + regularWidthLayoutConstraints = [ + backgroundView.leftAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.leftAnchor, constant: insets.left).with(priority: UILayoutPriority(rawValue: 900)), + backgroundView.rightAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.rightAnchor, constant: -insets.right).with(priority: UILayoutPriority(rawValue: 900)), + backgroundView.widthAnchor.constraint(lessThanOrEqualToConstant: 500).with(priority: UILayoutPriority(rawValue: 950)), + backgroundView.widthAnchor.constraint(equalToConstant: 500).with(priority: UILayoutPriority(rawValue: 200)), + ] installTapRecognizer() } @@ -139,23 +131,20 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab } addSubview(backgroundView) self.backgroundView = backgroundView - NSLayoutConstraint.activate([ - backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor) - .with(priority: .belowMessageSizeable), - backgroundView.topAnchor.constraint(equalTo: topAnchor, constant: insets.top) - .with(priority: .required), - backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -insets.bottom) - .with(priority: .required), - backgroundView.heightAnchor.constraint(equalToConstant: 350) - .with(priority: UILayoutPriority(rawValue: 200)), - backgroundView.leftAnchor.constraint( - equalTo: layoutMarginsGuide.leftAnchor, constant: insets.left - ).with(priority: .belowMessageSizeable), - backgroundView.rightAnchor.constraint( - equalTo: layoutMarginsGuide.rightAnchor, - constant: -insets.right - ).with(priority: .belowMessageSizeable), - ]) + backgroundView.centerXAnchor.constraint(equalTo: centerXAnchor).with(priority: UILayoutPriority(rawValue: 950)).isActive = true + backgroundView.topAnchor.constraint(equalTo: topAnchor, constant: insets.top).with(priority: UILayoutPriority(rawValue: 1000)).isActive = true + backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -insets.bottom).with(priority: UILayoutPriority(rawValue: 1000)).isActive = true + backgroundView.heightAnchor.constraint(equalToConstant: 350).with(priority: UILayoutPriority(rawValue: 200)).isActive = true + layoutConstraints = [ + backgroundView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor, constant: insets.left).with(priority: UILayoutPriority(rawValue: 900)), + backgroundView.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor, constant: -insets.right).with(priority: UILayoutPriority(rawValue: 900)), + ] + regularWidthLayoutConstraints = [ + backgroundView.leftAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.leftAnchor, constant: insets.left).with(priority: UILayoutPriority(rawValue: 900)), + backgroundView.rightAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.rightAnchor, constant: -insets.right).with(priority: UILayoutPriority(rawValue: 900)), + backgroundView.widthAnchor.constraint(lessThanOrEqualToConstant: 500).with(priority: UILayoutPriority(rawValue: 950)), + backgroundView.widthAnchor.constraint(equalToConstant: 500).with(priority: UILayoutPriority(rawValue: 200)), + ] installTapRecognizer() } @@ -201,14 +190,6 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab return super.point(inside: point, with: event) } - // MARK: - MessageSizeable - - /// Configure the view's size - public var messageSize = MessageSize() - - /// Configure the view's insets from the container - public var messageInsets = MessageInsets() - /* MARK: - MarginAdjustable @@ -248,6 +229,13 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab @IBInspectable open var bounceAnimationOffset: CGFloat = 5 + /* + MARK: - HasBoundaryInsets + */ + + /// Configure the view's inset from the superview or save area + public var boundaryInsets = BoundaryInsets() + /* MARK: - Setting the height */ @@ -276,6 +264,29 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, MessageSizeab } private var backgroundHeightConstraint: NSLayoutConstraint? + + /* + Mark: - Layout + */ + + open override func updateConstraints() { + super.updateConstraints() + let on: [NSLayoutConstraint] + let off: [NSLayoutConstraint] + switch traitCollection.horizontalSizeClass { + case .regular: + on = regularWidthLayoutConstraints + off = layoutConstraints + default: + on = layoutConstraints + off = regularWidthLayoutConstraints + } + on.forEach { $0.isActive = true } + off.forEach { $0.isActive = false } + } + + private var layoutConstraints: [NSLayoutConstraint] = [] + private var regularWidthLayoutConstraints: [NSLayoutConstraint] = [] } /* diff --git a/SwiftMessages/BoundaryInsets.swift b/SwiftMessages/BoundaryInsets.swift new file mode 100644 index 00000000..f3d1da60 --- /dev/null +++ b/SwiftMessages/BoundaryInsets.swift @@ -0,0 +1,41 @@ +// +// BoundaryInsets.swift +// SwiftMessages +// +// Created by Timothy Moose on 2/13/21. +// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. +// + +import QuartzCore + +public protocol HasBoundaryInsets { + var boundaryInsets: BoundaryInsets { get } +} + +/// Insets used for specifying view sizing options in terms of insets from the containing superview or safe area. +public struct BoundaryInsets { + + public enum Boundary { + case superview + case safeArea + case margin + } + + /// An abstract dimension used for specifying the message view's size + public enum Dimension { + + /// Dimensions should be determined automatically + case automatic + + /// Dimension should maintain an absolute margin to the given boundary. + case absoluteMargin(CGFloat, with: Boundary) + + /// Dimension should maintain a relative margin to the given boundary. + case relativeMargin(CGFloat, with: Boundary) + } + + public var top: Dimension = .automatic + public var bottom: Dimension = .automatic + public var leading: Dimension = .automatic + public var trailing: Dimension = .automatic +} diff --git a/SwiftMessages/MaskingView.swift b/SwiftMessages/MaskingView.swift index 889ac9de..0ce4c428 100644 --- a/SwiftMessages/MaskingView.swift +++ b/SwiftMessages/MaskingView.swift @@ -8,31 +8,8 @@ import UIKit -// TODO SIZE - need a version of this logic to limit views to 500pt on regular size class by default. -// regularWidthLayoutConstraints = [ -// backgroundView.leftAnchor.constraint( -// greaterThanOrEqualTo: layoutMarginsGuide.leftAnchor, -// constant: insets.left -// ).with(priority: .belowMessageSizeable), -// backgroundView.rightAnchor.constraint( -// lessThanOrEqualTo: layoutMarginsGuide.rightAnchor, -// constant: -insets.right -// ).with(priority: .belowMessageSizeable), -// backgroundView.widthAnchor.constraint(lessThanOrEqualToConstant: 500) -// .with(priority: .belowMessageSizeable), -// backgroundView.widthAnchor.constraint(equalToConstant: 500) -// .with(priority: UILayoutPriority(rawValue: 200)), -// ] -class MaskingView: PassthroughView, MessageSizing { - - func install(sizeableView: MessageSizeable & UIView) { - self.sizeableView?.removeFromSuperview() - self.sizeableView = sizeableView - sizeableView.translatesAutoresizingMaskIntoConstraints = false - addSubview(sizeableView) - setNeedsUpdateConstraints() - } +class MaskingView: PassthroughView { func install(keyboardTrackingView: KeyboardTrackingView) { self.keyboardTrackingView = keyboardTrackingView @@ -73,30 +50,15 @@ class MaskingView: PassthroughView, MessageSizing { init() { super.init(frame: CGRect.zero) - postInit() + clipsToBounds = true } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - postInit() - } - - private func postInit() { clipsToBounds = true - addLayoutGuide(messageInsetsGuide) - } - - override var bounds: CGRect { - didSet { - guard bounds != oldValue else { return } - setNeedsUpdateConstraints() - } } private var keyboardTrackingView: KeyboardTrackingView? - private var cachedConstraints: [NSLayoutConstraint] = [] - private let messageInsetsGuide = UILayoutGuide() - private var sizeableView: (MessageSizeable & UIView)? override func addSubview(_ view: UIView) { super.addSubview(view) @@ -105,175 +67,4 @@ class MaskingView: PassthroughView, MessageSizing { view != backgroundView else { return } keyboardTrackingView.topAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor).with(priority: UILayoutPriority(250)).isActive = true } - - override func updateConstraints() { - super.updateConstraints() - NSLayoutConstraint.deactivate(cachedConstraints) - cachedConstraints = [] - if let top = sizeableView?.messageInsets.top { update(top: top) } - if let bottom = sizeableView?.messageInsets.bottom { update(bottom: bottom) } - if let leading = sizeableView?.messageInsets.leading { update(leading: leading) } - if let trailing = sizeableView?.messageInsets.trailing { update(trailing: trailing) } - if let sizeableView = sizeableView { update(sizeableView: sizeableView) } - NSLayoutConstraint.activate(cachedConstraints) - } - - private func update(top: MessageInsets.Dimension) { - let length: CGFloat - switch top { - case .absoluteMargin(let dimension, _): - length = dimension - case .relativeMargin(let percentage, _): - length = bounds.height * percentage - } - let otherAnchor: NSLayoutYAxisAnchor - switch top.boundary { - case .superview: otherAnchor = topAnchor - case .margin: otherAnchor = layoutMarginsGuide.topAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = safeAreaLayoutGuide.topAnchor - } else { - otherAnchor = layoutMarginsGuide.topAnchor - } - } - cachedConstraints.append( - messageInsetsGuide.topAnchor.constraint(equalTo: otherAnchor, constant: length) - .with(priority: .messageInset) - ) - } - - private func update(bottom: MessageInsets.Dimension) { - let length: CGFloat - switch bottom { - case .absoluteMargin(let dimension, _): - length = dimension - case .relativeMargin(let percentage, _): - length = bounds.height * percentage - } - let otherAnchor: NSLayoutYAxisAnchor - switch bottom.boundary { - case .superview: otherAnchor = bottomAnchor - case .margin: otherAnchor = layoutMarginsGuide.bottomAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = safeAreaLayoutGuide.bottomAnchor - } else { - otherAnchor = layoutMarginsGuide.bottomAnchor - } - } - cachedConstraints.append( - messageInsetsGuide.bottomAnchor.constraint(equalTo: otherAnchor, constant: -length) - .with(priority: .messageInset) - ) - } - - private func update(leading: MessageInsets.Dimension) { - let length: CGFloat - switch leading { - case .absoluteMargin(let dimension, _): - length = dimension - case .relativeMargin(let percentage, _): - length = bounds.width * percentage - } - let otherAnchor: NSLayoutXAxisAnchor - switch leading.boundary { - case .superview: otherAnchor = leadingAnchor - case .margin: otherAnchor = layoutMarginsGuide.leadingAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = safeAreaLayoutGuide.leadingAnchor - } else { - otherAnchor = layoutMarginsGuide.leadingAnchor - } - } - cachedConstraints.append( - messageInsetsGuide.leadingAnchor.constraint(equalTo: otherAnchor, constant: length) - .with(priority: .messageInset) - ) - } - - private func update(trailing: MessageInsets.Dimension) { - let length: CGFloat - switch trailing { - case .absoluteMargin(let dimension, _): - length = dimension - case .relativeMargin(let percentage, _): - length = bounds.width * percentage - } - let otherAnchor: NSLayoutXAxisAnchor - switch trailing.boundary { - case .superview: otherAnchor = trailingAnchor - case .margin: otherAnchor = layoutMarginsGuide.trailingAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = safeAreaLayoutGuide.trailingAnchor - } else { - otherAnchor = layoutMarginsGuide.trailingAnchor - } - } - cachedConstraints.append( - messageInsetsGuide.trailingAnchor.constraint(equalTo: otherAnchor, constant: -length) - .with(priority: .messageInset) - ) - } - - private func update(sizeableView view: MessageSizeable & UIView) { - cachedConstraints += [ - messageInsetsGuide.topAnchor.constraint(equalTo: view.topAnchor), - messageInsetsGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor), - messageInsetsGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor), - messageInsetsGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor), - ] - if let width = view.messageSize.width { - let length = self.length(for: width, extractor: { $0.width }) - cachedConstraints.append( - view.widthAnchor.constraint(equalToConstant: length) - .with(priority: .messageSize) - ) - } - if let height = view.messageSize.height { - let length = self.length(for: height, extractor: { $0.height }) - cachedConstraints.append( - view.heightAnchor.constraint(equalToConstant: length) - .with(priority: .messageSize) - ) - } - } - - private func length( - for dimension: MessageSize.Dimension, - extractor: (CGRect) -> CGFloat - ) -> CGFloat { - switch dimension { - case .absolute(let dimension): - return dimension - case .absoluteMargin(let margin, let boundary): - let insets: UIEdgeInsets - switch boundary { - case .superview: insets = .zero - case .margin: insets = layoutMargins - case .safeArea: - if #available(iOS 11.0, *) { - insets = safeAreaInsets - } else { - insets = layoutMargins - } - } - return extractor(bounds.inset(by: insets)) - margin * 2 - case .relative(let percentage, let boundary): - let insets: UIEdgeInsets - switch boundary { - case .superview: insets = .zero - case .margin: insets = layoutMargins - case .safeArea: - if #available(iOS 11.0, *) { - insets = safeAreaInsets - } else { - insets = layoutMargins - } - } - return extractor(bounds.inset(by: insets)) * percentage - } - } } diff --git a/SwiftMessages/MessageSizeable.swift b/SwiftMessages/MessageSizeable.swift deleted file mode 100644 index 662f1839..00000000 --- a/SwiftMessages/MessageSizeable.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// BoundaryInsets.swift -// SwiftMessages -// -// Created by Timothy Moose on 2/13/21. -// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. -// - -import UIKit - -public protocol MessageSizeable { - var messageSize: MessageSize { get } - var messageInsets: MessageInsets { get } -} - -public enum MessageBoundary { - case superview - case safeArea - case margin -} - -/// Insets used for specifying view sizing options in terms of insets from the containing superview or safe area. -public struct MessageInsets { - - public enum Dimension { - - /// Dimension should maintain an absolute margin to the given container boundary. - case absoluteMargin(CGFloat, from: MessageBoundary) - - /// Dimension should maintain a relative margin to the given container boundary. - case relativeMargin(CGFloat, from: MessageBoundary) - } - - public var top: Dimension? - public var bottom: Dimension? - public var leading: Dimension? - public var trailing: Dimension? -} - -public struct MessageSize { - - public enum Dimension { - - /// Dimensions should be an absolute length - case absolute(CGFloat) - - /// Dimension should maintain an absolute length to the given container boundary. - case absoluteMargin(CGFloat, from: MessageBoundary) - - /// Dimension should maintain a relative margin to the given boundary. - case relative(CGFloat, from: MessageBoundary) - } - - public var width: Dimension? - public var height: Dimension? -} - -extension MessageInsets.Dimension { - var boundary: MessageBoundary { - switch self { - case .absoluteMargin(_, let boundary): return boundary - case .relativeMargin(_, let boundary): return boundary - } - } -} diff --git a/SwiftMessages/MessageSizing.swift b/SwiftMessages/MessageSizing.swift deleted file mode 100644 index b4c47dd3..00000000 --- a/SwiftMessages/MessageSizing.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// MessageSizing.swift -// SwiftMessages -// -// Created by Timothy Moose on 2/14/21. -// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. -// - -import Foundation - -public protocol MessageSizing { - func install(sizeableView: MessageSizeable & UIView) -} diff --git a/SwiftMessages/Resources/CardView.xib b/SwiftMessages/Resources/CardView.xib index f3ad1df4..425a6961 100644 --- a/SwiftMessages/Resources/CardView.xib +++ b/SwiftMessages/Resources/CardView.xib @@ -1,9 +1,9 @@ - + - + @@ -70,6 +70,7 @@ + @@ -77,13 +78,25 @@ + + + + + + + + + + + + @@ -106,10 +119,18 @@ + + + + + + + + diff --git a/SwiftMessages/Resources/CenteredView.xib b/SwiftMessages/Resources/CenteredView.xib index b61242cc..a9fda2be 100644 --- a/SwiftMessages/Resources/CenteredView.xib +++ b/SwiftMessages/Resources/CenteredView.xib @@ -1,9 +1,9 @@ - + - + @@ -32,7 +32,7 @@ + + + + + + + + + + @@ -85,8 +96,10 @@ + + @@ -109,10 +122,18 @@ + + + + + + + + diff --git a/SwiftMessages/Resources/TabView.xib b/SwiftMessages/Resources/TabView.xib index e572aa41..141467c1 100644 --- a/SwiftMessages/Resources/TabView.xib +++ b/SwiftMessages/Resources/TabView.xib @@ -1,9 +1,9 @@ - + - + @@ -69,6 +69,7 @@ + @@ -77,15 +78,27 @@ + + + + + + + + + + + + @@ -108,8 +121,16 @@ + + + + + + + + diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index f20491bc..8fa696ed 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -369,15 +369,11 @@ extension SwiftMessagesSegue { if let preferredHeight = toVC?.preferredContentSize.height, preferredHeight - navInset > 0 { - segue.containerView.heightAnchor.constraint(equalToConstant: preferredHeight) - .with(priority: .belowMessageSizeable - 1) - .isActive = true + segue.containerView.heightAnchor.constraint(equalToConstant: preferredHeight).with(priority: UILayoutPriority(rawValue: 951)).isActive = true } if let preferredWidth = toVC?.preferredContentSize.width, preferredWidth > 0 { - segue.containerView.widthAnchor.constraint(equalToConstant: preferredWidth) - .with(priority: .belowMessageSizeable - 1) - .isActive = true + segue.containerView.widthAnchor.constraint(equalToConstant: preferredWidth).with(priority: UILayoutPriority(rawValue: 951)).isActive = true } segue.presenter.config.presentationContext = .view(transitionContainer) segue.messenger.show(presenter: segue.presenter) diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index 0a91fc3f..78c0d84a 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -88,30 +88,92 @@ public class TopBottomAnimation: NSObject, Animator { if let adjustable = context.messageView as? MarginAdjustable { bounceOffset = adjustable.bounceAnimationOffset } - if let sizeableView = view as? MessageSizeable & UIView { - container.install(sizeableView: sizeableView) - } else { - view.translatesAutoresizingMaskIntoConstraints = false - container.addSubview(view) - } - // Horizontal constraints - do { - view.leadingAnchor.constraint(equalTo: container.leadingAnchor) - .with(priority: .belowMessageSizeable - 1) - .isActive = true - view.centerXAnchor.constraint(equalTo: container.centerXAnchor) - .with(priority: .belowMessageSizeable) - .isActive = true - } + view.translatesAutoresizingMaskIntoConstraints = false + container.addSubview(view) + view.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true + view.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true + let boundaryInsets = (view as? HasBoundaryInsets)?.boundaryInsets ?? BoundaryInsets() switch style { case .top: - view.topAnchor.constraint(equalTo: container.topAnchor, constant: -bounceOffset) - .with(priority: .belowMessageSizeable) - .isActive = true + view.topAnchor.constraint( + equalTo: container.topAnchor, + constant: -bounceOffset + ).with(priority: .defaultHigh).isActive = true + switch boundaryInsets.bottom { + case .automatic: + break + case .absoluteMargin(let dimension, let boundary): + let otherAnchor: NSLayoutYAxisAnchor + switch boundary { + case .superview: otherAnchor = container.bottomAnchor + case .safeArea: + if #available(iOS 11.0, *) { + otherAnchor = container.safeAreaLayoutGuide.bottomAnchor + } else { + otherAnchor = container.layoutMarginsGuide.bottomAnchor + } + case .margin: otherAnchor = container.layoutMarginsGuide.bottomAnchor + } + view.bottomAnchor.constraint(equalTo: otherAnchor, constant: -dimension) + .with(priority: .defaultHigh) + .isActive = true + case .relativeMargin(let dimension, let boundary): + let otherAnchor: NSLayoutDimension! + switch boundary { + case .superview: otherAnchor = container.heightAnchor + case .safeArea: + if #available(iOS 11.0, *) { + otherAnchor = container.safeAreaLayoutGuide.heightAnchor + } else { + otherAnchor = container.layoutMarginsGuide.heightAnchor + } + case .margin: otherAnchor = container.layoutMarginsGuide.heightAnchor + } + view.heightAnchor.constraint( + equalTo: otherAnchor, + multiplier: 1 - dimension + ).with(priority: .defaultHigh).isActive = true + } case .bottom: - view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: bounceOffset) - .with(priority: .belowMessageSizeable) - .isActive = true + view.bottomAnchor.constraint( + equalTo: container.bottomAnchor, + constant: bounceOffset + ).with(priority: .defaultHigh).isActive = true + switch boundaryInsets.top { + case .automatic: + break + case .absoluteMargin(let dimension, let boundary): + let otherAnchor: NSLayoutYAxisAnchor + switch boundary { + case .superview: otherAnchor = container.topAnchor + case .safeArea: + if #available(iOS 11.0, *) { + otherAnchor = container.safeAreaLayoutGuide.topAnchor + } else { + otherAnchor = container.layoutMarginsGuide.topAnchor + } + case .margin: otherAnchor = container.layoutMarginsGuide.topAnchor + } + view.topAnchor.constraint(equalTo: otherAnchor, constant: dimension) + .with(priority: .defaultHigh) + .isActive = true + case .relativeMargin(let dimension, let boundary): + let otherAnchor: NSLayoutDimension! + switch boundary { + case .superview: otherAnchor = container.heightAnchor + case .safeArea: + if #available(iOS 11.0, *) { + otherAnchor = container.safeAreaLayoutGuide.heightAnchor + } else { + otherAnchor = container.layoutMarginsGuide.heightAnchor + } + case .margin: otherAnchor = container.layoutMarginsGuide.heightAnchor + } + view.heightAnchor.constraint( + equalTo: otherAnchor, + multiplier: 1 - dimension + ).with(priority: .defaultHigh).isActive = true + } } // Important to layout now in order to get the right safe area insets container.layoutIfNeeded() diff --git a/SwiftMessages/UILayoutPriority+Extensions.swift b/SwiftMessages/UILayoutPriority+Extensions.swift deleted file mode 100644 index 1fd3ab88..00000000 --- a/SwiftMessages/UILayoutPriority+Extensions.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// UILayoutPriority+Extensions.swift -// SwiftMessages -// -// Created by Timothy Moose on 2/14/21. -// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. -// - -import UIKit - -/// The priority used for `MessageSizeable` constraints -public extension UILayoutPriority { - static let aboveMessageSizeable: UILayoutPriority = messageInset + 1 - static let belowMessageSizeable: UILayoutPriority = messageSize - 1 - static let messageSize: UILayoutPriority = UILayoutPriority(900) - static let messageInset: UILayoutPriority = UILayoutPriority(901) -} - From 551e147ee4fab10bd9333e8333fb71f623e3c92f Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:33:43 -0500 Subject: [PATCH 097/139] Revert "Consider nav bar behavior in preferred content size" This reverts commit 46ad7377bc1a4191e9967f5f083b8a362510468b. --- SwiftMessages/SwiftMessagesSegue.swift | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index 8fa696ed..d4cba417 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -359,16 +359,8 @@ extension SwiftMessagesSegue { segue.messageView.installBackgroundVerticalView(segue.containerView) } let toVC = transitionContext.viewController(forKey: .to) - - // Nav controller automatically includes height of nav bar in, - // the `preferredContentSize` and our logic needs to consider this. - var navInset: CGFloat = 0 - if let nav = toVC as? UINavigationController { - navInset = nav.navigationBar.frame.height - } - if let preferredHeight = toVC?.preferredContentSize.height, - preferredHeight - navInset > 0 { + preferredHeight > 0 { segue.containerView.heightAnchor.constraint(equalToConstant: preferredHeight).with(priority: UILayoutPriority(rawValue: 951)).isActive = true } if let preferredWidth = toVC?.preferredContentSize.width, From 8900f82cf656f030b6bfa607150d98013191079a Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:33:52 -0500 Subject: [PATCH 098/139] Revert "Keep support for iOS 10" This reverts commit 0ee863a30c17b907d2f0290f277a50c949bb48b1. --- SwiftMessages.podspec | 4 ++-- SwiftMessages.xcodeproj/project.pbxproj | 8 +++---- SwiftMessages/TopBottomAnimation.swift | 28 ++++--------------------- 3 files changed, 10 insertions(+), 30 deletions(-) diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index aad0b316..130843c5 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -6,9 +6,9 @@ Pod::Spec.new do |spec| spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } spec.summary = 'A very flexible message bar for iOS written in Swift.' spec.source = {:git => 'https://github.com/SwiftKickMobile/SwiftMessages.git', :tag => spec.version} - spec.platform = :ios, '10.0' + spec.platform = :ios, '11.0' spec.swift_version = '5.0' - spec.ios.deployment_target = '10.0' + spec.ios.deployment_target = '11.0' spec.framework = 'UIKit' spec.requires_arc = true spec.default_subspec = 'App' diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index f5296fde..abec6078 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -630,7 +630,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -682,7 +682,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -704,7 +704,7 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessages; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -732,7 +732,7 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessages; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index 78c0d84a..0a7dc19e 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -106,12 +106,7 @@ public class TopBottomAnimation: NSObject, Animator { let otherAnchor: NSLayoutYAxisAnchor switch boundary { case .superview: otherAnchor = container.bottomAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = container.safeAreaLayoutGuide.bottomAnchor - } else { - otherAnchor = container.layoutMarginsGuide.bottomAnchor - } + case .safeArea: otherAnchor = container.safeAreaLayoutGuide.bottomAnchor case .margin: otherAnchor = container.layoutMarginsGuide.bottomAnchor } view.bottomAnchor.constraint(equalTo: otherAnchor, constant: -dimension) @@ -121,12 +116,7 @@ public class TopBottomAnimation: NSObject, Animator { let otherAnchor: NSLayoutDimension! switch boundary { case .superview: otherAnchor = container.heightAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = container.safeAreaLayoutGuide.heightAnchor - } else { - otherAnchor = container.layoutMarginsGuide.heightAnchor - } + case .safeArea: otherAnchor = container.safeAreaLayoutGuide.heightAnchor case .margin: otherAnchor = container.layoutMarginsGuide.heightAnchor } view.heightAnchor.constraint( @@ -146,12 +136,7 @@ public class TopBottomAnimation: NSObject, Animator { let otherAnchor: NSLayoutYAxisAnchor switch boundary { case .superview: otherAnchor = container.topAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = container.safeAreaLayoutGuide.topAnchor - } else { - otherAnchor = container.layoutMarginsGuide.topAnchor - } + case .safeArea: otherAnchor = container.safeAreaLayoutGuide.topAnchor case .margin: otherAnchor = container.layoutMarginsGuide.topAnchor } view.topAnchor.constraint(equalTo: otherAnchor, constant: dimension) @@ -161,12 +146,7 @@ public class TopBottomAnimation: NSObject, Animator { let otherAnchor: NSLayoutDimension! switch boundary { case .superview: otherAnchor = container.heightAnchor - case .safeArea: - if #available(iOS 11.0, *) { - otherAnchor = container.safeAreaLayoutGuide.heightAnchor - } else { - otherAnchor = container.layoutMarginsGuide.heightAnchor - } + case .safeArea: otherAnchor = container.safeAreaLayoutGuide.heightAnchor case .margin: otherAnchor = container.layoutMarginsGuide.heightAnchor } view.heightAnchor.constraint( From 77d3e953481559a59a3dd22c342c346f20c40e37 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:33:59 -0500 Subject: [PATCH 099/139] Revert "BoundaryInsets prototype" This reverts commit fbfbf3c1e6b0d152be878627e7f54904d921a7f6. --- SwiftMessages.podspec | 6 +-- SwiftMessages.xcodeproj/project.pbxproj | 12 ++--- SwiftMessages/Animator.swift | 8 +--- SwiftMessages/BaseView.swift | 9 +--- SwiftMessages/BoundaryInsets.swift | 41 ---------------- SwiftMessages/TopBottomAnimation.swift | 63 +------------------------ 6 files changed, 12 insertions(+), 127 deletions(-) delete mode 100644 SwiftMessages/BoundaryInsets.swift diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 130843c5..22b2d781 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.1.0' + spec.version = '9.0.0' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } spec.summary = 'A very flexible message bar for iOS written in Swift.' spec.source = {:git => 'https://github.com/SwiftKickMobile/SwiftMessages.git', :tag => spec.version} - spec.platform = :ios, '11.0' + spec.platform = :ios, '9.0' spec.swift_version = '5.0' - spec.ios.deployment_target = '11.0' + spec.ios.deployment_target = '9.0' spec.framework = 'UIKit' spec.requires_arc = true spec.default_subspec = 'App' diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index abec6078..95f93353 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -51,7 +51,6 @@ 228DF5681FAD0806004F8A39 /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */; }; 228DF5691FAD0806004F8A39 /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5481FAD0805004F8A39 /* successIconLight.png */; }; 228DF56A1FAD0806004F8A39 /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */; }; - 2290944825D88A05002E8111 /* BoundaryInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2290944725D88A05002E8111 /* BoundaryInsets.swift */; }; 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; @@ -138,7 +137,6 @@ 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = infoIconSubtle.png; path = Resources/infoIconSubtle.png; sourceTree = ""; }; 228DF5481FAD0805004F8A39 /* successIconLight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = successIconLight.png; path = Resources/successIconLight.png; sourceTree = ""; }; 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; - 2290944725D88A05002E8111 /* BoundaryInsets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoundaryInsets.swift; sourceTree = ""; }; 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; @@ -300,7 +298,6 @@ 22E307FE1E74C5B100E35893 /* AccessibleMessage.swift */, 86AAF82A1D580DD70031EE32 /* Error.swift */, 2298C2061EE480D000E2DDC1 /* Animator.swift */, - 2290944725D88A05002E8111 /* BoundaryInsets.swift */, 2298C2041EE47DC900E2DDC1 /* Weak.swift */, 22F27950210CE25900273E7F /* CornerRoundingView.swift */, 225304652293000C00A03ACF /* KeyboardTrackingView.swift */, @@ -533,7 +530,6 @@ 86BBA8FC1D5E03F100FE8F16 /* MessageView.swift in Sources */, 86BBA9061D5E040C00FE8F16 /* Identifiable.swift in Sources */, 22F27951210CE25900273E7F /* CornerRoundingView.swift in Sources */, - 2290944825D88A05002E8111 /* BoundaryInsets.swift in Sources */, 86BBA9011D5E040600FE8F16 /* PassthroughWindow.swift in Sources */, 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */, 86BBA9031D5E040600FE8F16 /* UIViewController+Extensions.swift in Sources */, @@ -630,7 +626,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -682,7 +678,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -704,7 +700,7 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessages; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -732,7 +728,7 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessages; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/SwiftMessages/Animator.swift b/SwiftMessages/Animator.swift index b95bcaf9..7d924e2d 100644 --- a/SwiftMessages/Animator.swift +++ b/SwiftMessages/Animator.swift @@ -44,17 +44,13 @@ public struct SafeZoneConflicts: OptionSet { } public class AnimationContext { + public let messageView: UIView public let containerView: UIView public let safeZoneConflicts: SafeZoneConflicts public let interactiveHide: Bool - internal init( - messageView: UIView, - containerView: UIView, - safeZoneConflicts: SafeZoneConflicts, - interactiveHide: Bool - ) { + init(messageView: UIView, containerView: UIView, safeZoneConflicts: SafeZoneConflicts, interactiveHide: Bool) { self.messageView = messageView self.containerView = containerView self.safeZoneConflicts = safeZoneConflicts diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index 93c9df96..9480b87d 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -14,7 +14,7 @@ import UIKit of the optional SwiftMessages protocols and provides some convenience functions and a configurable tap handler. Message views do not need to inherit from `BaseVew`. */ -open class BaseView: UIView, BackgroundViewable, MarginAdjustable, HasBoundaryInsets { +open class BaseView: UIView, BackgroundViewable, MarginAdjustable { /* MARK: - IB outlets @@ -229,13 +229,6 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable, HasBoundaryIn @IBInspectable open var bounceAnimationOffset: CGFloat = 5 - /* - MARK: - HasBoundaryInsets - */ - - /// Configure the view's inset from the superview or save area - public var boundaryInsets = BoundaryInsets() - /* MARK: - Setting the height */ diff --git a/SwiftMessages/BoundaryInsets.swift b/SwiftMessages/BoundaryInsets.swift deleted file mode 100644 index f3d1da60..00000000 --- a/SwiftMessages/BoundaryInsets.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// BoundaryInsets.swift -// SwiftMessages -// -// Created by Timothy Moose on 2/13/21. -// Copyright Β© 2021 SwiftKick Mobile. All rights reserved. -// - -import QuartzCore - -public protocol HasBoundaryInsets { - var boundaryInsets: BoundaryInsets { get } -} - -/// Insets used for specifying view sizing options in terms of insets from the containing superview or safe area. -public struct BoundaryInsets { - - public enum Boundary { - case superview - case safeArea - case margin - } - - /// An abstract dimension used for specifying the message view's size - public enum Dimension { - - /// Dimensions should be determined automatically - case automatic - - /// Dimension should maintain an absolute margin to the given boundary. - case absoluteMargin(CGFloat, with: Boundary) - - /// Dimension should maintain a relative margin to the given boundary. - case relativeMargin(CGFloat, with: Boundary) - } - - public var top: Dimension = .automatic - public var bottom: Dimension = .automatic - public var leading: Dimension = .automatic - public var trailing: Dimension = .automatic -} diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index 0a7dc19e..d9f1f3a4 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -19,8 +19,6 @@ public class TopBottomAnimation: NSObject, Animator { public let style: Style - open var heightDimension: Dimension? - open var showDuration: TimeInterval = 0.4 open var hideDuration: TimeInterval = 0.2 @@ -92,68 +90,11 @@ public class TopBottomAnimation: NSObject, Animator { container.addSubview(view) view.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true view.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true - let boundaryInsets = (view as? HasBoundaryInsets)?.boundaryInsets ?? BoundaryInsets() switch style { case .top: - view.topAnchor.constraint( - equalTo: container.topAnchor, - constant: -bounceOffset - ).with(priority: .defaultHigh).isActive = true - switch boundaryInsets.bottom { - case .automatic: - break - case .absoluteMargin(let dimension, let boundary): - let otherAnchor: NSLayoutYAxisAnchor - switch boundary { - case .superview: otherAnchor = container.bottomAnchor - case .safeArea: otherAnchor = container.safeAreaLayoutGuide.bottomAnchor - case .margin: otherAnchor = container.layoutMarginsGuide.bottomAnchor - } - view.bottomAnchor.constraint(equalTo: otherAnchor, constant: -dimension) - .with(priority: .defaultHigh) - .isActive = true - case .relativeMargin(let dimension, let boundary): - let otherAnchor: NSLayoutDimension! - switch boundary { - case .superview: otherAnchor = container.heightAnchor - case .safeArea: otherAnchor = container.safeAreaLayoutGuide.heightAnchor - case .margin: otherAnchor = container.layoutMarginsGuide.heightAnchor - } - view.heightAnchor.constraint( - equalTo: otherAnchor, - multiplier: 1 - dimension - ).with(priority: .defaultHigh).isActive = true - } + view.topAnchor.constraint(equalTo: container.topAnchor, constant: -bounceOffset).with(priority: UILayoutPriority(200)).isActive = true case .bottom: - view.bottomAnchor.constraint( - equalTo: container.bottomAnchor, - constant: bounceOffset - ).with(priority: .defaultHigh).isActive = true - switch boundaryInsets.top { - case .automatic: - break - case .absoluteMargin(let dimension, let boundary): - let otherAnchor: NSLayoutYAxisAnchor - switch boundary { - case .superview: otherAnchor = container.topAnchor - case .safeArea: otherAnchor = container.safeAreaLayoutGuide.topAnchor - case .margin: otherAnchor = container.layoutMarginsGuide.topAnchor - } - view.topAnchor.constraint(equalTo: otherAnchor, constant: dimension) - .with(priority: .defaultHigh) - .isActive = true - case .relativeMargin(let dimension, let boundary): - let otherAnchor: NSLayoutDimension! - switch boundary { - case .superview: otherAnchor = container.heightAnchor - case .safeArea: otherAnchor = container.safeAreaLayoutGuide.heightAnchor - case .margin: otherAnchor = container.layoutMarginsGuide.heightAnchor - } - view.heightAnchor.constraint( - equalTo: otherAnchor, - multiplier: 1 - dimension - ).with(priority: .defaultHigh).isActive = true - } + view.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: bounceOffset).with(priority: UILayoutPriority(200)).isActive = true } // Important to layout now in order to get the right safe area insets container.layoutIfNeeded() From 6925ef9f8f19ce7fef2bf3fbe4dcf5fc99d471e0 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 10 Apr 2021 16:43:36 -0500 Subject: [PATCH 100/139] Fix merge error --- SwiftMessages.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 95f93353..5103fcdd 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -54,6 +54,7 @@ 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; + 229F778125FAB1E9008C2ACB /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */; }; 22DFC9161EFF30F6001B1CA1 /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */; }; 22DFC9181F00674E001B1CA1 /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */; }; 22E01F641E74EC8B00ACE19A /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22E01F631E74EC8B00ACE19A /* MaskingView.swift */; }; @@ -140,6 +141,7 @@ 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; + 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Extensions.swift"; sourceTree = ""; }; 22A2EA6E24EC6CFA00BB2540 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CenteredView.xib; path = Resources/CenteredView.xib; sourceTree = ""; }; 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsPanHandler.swift; sourceTree = ""; }; @@ -209,6 +211,7 @@ children = ( 220655111FAF82B600F4E00F /* MarginAdjustable+Extensions.swift */, 22774B9F20B5EF2A00813732 /* UIEdgeInsets+Extensions.swift */, + 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */, ); name = Extensions; sourceTree = ""; From b4002f7ec293c426b26b8d1045b5f038cf446f02 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 3 Jun 2021 10:43:04 -0500 Subject: [PATCH 101/139] Fix Carthage build --- SwiftMessages.podspec | 2 +- iMessageDemo/Podfile | 19 +++++++++++++++++++ iMessageDemo/Podfile.lock | 6 +++--- .../Local Podspecs/SwiftMessages.podspec.json | 4 ++-- iMessageDemo/Pods/Manifest.lock | 6 +++--- .../contents.xcworkspacedata | 7 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++++++++ ...ges_SwiftMessages-SwiftMessages-Info.plist | 2 +- .../SwiftMessages/SwiftMessages-Info.plist | 2 +- .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++++++++ 11 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 820b4e9a..a6c018fa 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.2' + spec.version = '9.0.3' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } diff --git a/iMessageDemo/Podfile b/iMessageDemo/Podfile index 7c45a63f..7ae17852 100644 --- a/iMessageDemo/Podfile +++ b/iMessageDemo/Podfile @@ -1,6 +1,9 @@ # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' +install! 'cocoapods', + :share_schemes_for_development_pods => false + target 'iMessageDemo' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! @@ -17,3 +20,19 @@ target 'iMessageExtensionDemo' do pod 'SwiftMessages/AppExtension', :path => "../" end + +post_install do |installer| + # Blow away schemes – the schemes created by CocoaPods break Carthage builds + # because they incluede a SwiftMessages framework that Carthage picks + # over the main SwiftMessages framework. The SwiftMessages framework that gets + # picked is configured for an app extension and doesn't work correctly in an app. + File.directory?(path) + [ + "#{installer.sandbox.root}/Pods.xcodeproj/xcuserdata", + "#{installer.sandbox.root}/Pods.xcodeproj/xcshareddata" + ].each { |path| + if File.directory?(path) + FileUtils.remove_dir(path) + end + } +end diff --git a/iMessageDemo/Podfile.lock b/iMessageDemo/Podfile.lock index 552070e5..b7d82fb3 100644 --- a/iMessageDemo/Podfile.lock +++ b/iMessageDemo/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - SwiftMessages/AppExtension (9.0.1) + - SwiftMessages/AppExtension (9.0.3) DEPENDENCIES: - SwiftMessages/AppExtension (from `../`) @@ -9,8 +9,8 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - SwiftMessages: b71f53eb919887c0273bf43cbc002bd4f0cfb3d6 + SwiftMessages: 077f19126c24033fe24042237ecc20261adb46e4 -PODFILE CHECKSUM: 4cfafdad7d8903d0f4cfadbe05660bcdeff7c9e6 +PODFILE CHECKSUM: dde250cdcd60ccf6ec0a51da5a633d36b9f83a3b COCOAPODS: 1.10.0 diff --git a/iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json b/iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json index 72a5b097..6d9e93c9 100644 --- a/iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json +++ b/iMessageDemo/Pods/Local Podspecs/SwiftMessages.podspec.json @@ -1,6 +1,6 @@ { "name": "SwiftMessages", - "version": "9.0.1", + "version": "9.0.3", "license": { "type": "MIT" }, @@ -11,7 +11,7 @@ "summary": "A very flexible message bar for iOS written in Swift.", "source": { "git": "https://github.com/SwiftKickMobile/SwiftMessages.git", - "tag": "9.0.1" + "tag": "9.0.3" }, "platforms": { "ios": "9.0" diff --git a/iMessageDemo/Pods/Manifest.lock b/iMessageDemo/Pods/Manifest.lock index 552070e5..b7d82fb3 100644 --- a/iMessageDemo/Pods/Manifest.lock +++ b/iMessageDemo/Pods/Manifest.lock @@ -1,5 +1,5 @@ PODS: - - SwiftMessages/AppExtension (9.0.1) + - SwiftMessages/AppExtension (9.0.3) DEPENDENCIES: - SwiftMessages/AppExtension (from `../`) @@ -9,8 +9,8 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - SwiftMessages: b71f53eb919887c0273bf43cbc002bd4f0cfb3d6 + SwiftMessages: 077f19126c24033fe24042237ecc20261adb46e4 -PODFILE CHECKSUM: 4cfafdad7d8903d0f4cfadbe05660bcdeff7c9e6 +PODFILE CHECKSUM: dde250cdcd60ccf6ec0a51da5a633d36b9f83a3b COCOAPODS: 1.10.0 diff --git a/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..08de0be8 --- /dev/null +++ b/iMessageDemo/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist b/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist index 35c2f997..fa5d486a 100644 --- a/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist @@ -13,7 +13,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 9.0.1 + 9.0.3 CFBundleSignature ???? CFBundleVersion diff --git a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist index 2687f6bd..364cea2f 100644 --- a/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist +++ b/iMessageDemo/Pods/Target Support Files/SwiftMessages/SwiftMessages-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.1 + 9.0.3 CFBundleSignature ???? CFBundleVersion diff --git a/iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..08de0be8 --- /dev/null +++ b/iMessageDemo/iMessageDemo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + From 3a6fb3f4c2369441f17b340070b7409abe99d021 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 3 Jun 2021 10:58:48 -0500 Subject: [PATCH 102/139] Update changelog --- CHANGELOG.md | 6 ++++++ iMessageDemo/Podfile.lock | 2 +- iMessageDemo/Pods/Manifest.lock | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08f50bbb..f10c7f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.3 + +### Fixes + +* #465 - Fix broken Carthage build. The Carthage build was broken due to the `iMessageDemo` project's use of CocoaPods and the automatically generated `SwiftMessages` framework scheme created by CocoaPods. The podfile was modified to delete this scheme, but Carthage users may need to run `pod install` on the `iMessagesDemo` project, if they have CocoaPods installed, or manually delete the `iMessageDemo/Pods/Pods.xcodeproj/xcuserdata` folder. + ## 9.0.2 ### Fixes diff --git a/iMessageDemo/Podfile.lock b/iMessageDemo/Podfile.lock index b7d82fb3..54bd951e 100644 --- a/iMessageDemo/Podfile.lock +++ b/iMessageDemo/Podfile.lock @@ -11,6 +11,6 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: SwiftMessages: 077f19126c24033fe24042237ecc20261adb46e4 -PODFILE CHECKSUM: dde250cdcd60ccf6ec0a51da5a633d36b9f83a3b +PODFILE CHECKSUM: 2eb9a33592d0c52131c37a9dd169a8c4604ffd7b COCOAPODS: 1.10.0 diff --git a/iMessageDemo/Pods/Manifest.lock b/iMessageDemo/Pods/Manifest.lock index b7d82fb3..54bd951e 100644 --- a/iMessageDemo/Pods/Manifest.lock +++ b/iMessageDemo/Pods/Manifest.lock @@ -11,6 +11,6 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: SwiftMessages: 077f19126c24033fe24042237ecc20261adb46e4 -PODFILE CHECKSUM: dde250cdcd60ccf6ec0a51da5a633d36b9f83a3b +PODFILE CHECKSUM: 2eb9a33592d0c52131c37a9dd169a8c4604ffd7b COCOAPODS: 1.10.0 From af2a69303a8d1f1d9f6fae1bf987ad1d38e7813a Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 3 Jun 2021 11:33:55 -0500 Subject: [PATCH 103/139] Fix logic that identifies the keyWindow --- CHANGELOG.md | 3 ++- SwiftMessages/UIWindow+Extensions.swift | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f10c7f2c..17f749a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file. ### Fixes -* #465 - Fix broken Carthage build. The Carthage build was broken due to the `iMessageDemo` project's use of CocoaPods and the automatically generated `SwiftMessages` framework scheme created by CocoaPods. The podfile was modified to delete this scheme, but Carthage users may need to run `pod install` on the `iMessagesDemo` project, if they have CocoaPods installed, or manually delete the `iMessageDemo/Pods/Pods.xcodeproj/xcuserdata` folder. +* #466 Alert not shown after Biometry check +* #465 Fix broken Carthage build. The Carthage build was broken due to the `iMessageDemo` project's use of CocoaPods and the automatically generated `SwiftMessages` framework scheme created by CocoaPods. The podfile was modified to delete this scheme, but Carthage users may need to run `pod install` on the `iMessagesDemo` project, if they have CocoaPods installed, or manually delete the `iMessageDemo/Pods/Pods.xcodeproj/xcuserdata` folder. ## 9.0.2 diff --git a/SwiftMessages/UIWindow+Extensions.swift b/SwiftMessages/UIWindow+Extensions.swift index d98c6caf..316fcacd 100644 --- a/SwiftMessages/UIWindow+Extensions.swift +++ b/SwiftMessages/UIWindow+Extensions.swift @@ -13,10 +13,9 @@ extension UIWindow { static var keyWindow: UIWindow? { if #available(iOS 13.0, *) { return UIApplication.shared.connectedScenes - .filter { $0.activationState == .foregroundActive } + .sorted { $0.activationState.sortPriority < $1.activationState.sortPriority } .compactMap { $0 as? UIWindowScene } - .first?.windows - .filter { $0.isKeyWindow } + .compactMap { $0.windows.first { $0.isKeyWindow } } .first } else { return UIApplication.shared.keyWindow @@ -24,3 +23,16 @@ extension UIWindow { } #endif } + +@available(iOS 13.0, *) +private extension UIScene.ActivationState { + var sortPriority: Int { + switch self { + case .foregroundActive: return 1 + case .foregroundInactive: return 2 + case .background: return 3 + case .unattached: return 4 + @unknown default: return 5 + } + } +} From 402984b2171c28038894c73bed4467832041f4c7 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 3 Jun 2021 12:36:41 -0500 Subject: [PATCH 104/139] =?UTF-8?q?Fix=20467=20-=20don=E2=80=99t=20tell=20?= =?UTF-8?q?the=20previous=20window=20to=20become=20visible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SwiftMessages/WindowViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages/WindowViewController.swift b/SwiftMessages/WindowViewController.swift index 96b30095..9c2b721c 100644 --- a/SwiftMessages/WindowViewController.swift +++ b/SwiftMessages/WindowViewController.swift @@ -59,7 +59,7 @@ open class WindowViewController: UIViewController func uninstall() { if window?.isKeyWindow == true { - previousKeyWindow?.makeKeyAndVisible() + previousKeyWindow?.makeKey() } if #available(iOS 13, *) { window?.windowScene = nil From 2187a0c8f8c8a11aa73f05fa915be3cc9c36f240 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Thu, 3 Jun 2021 12:37:54 -0500 Subject: [PATCH 105/139] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17f749a1..d44911cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Fixes +* #467 Lower or equal level window's views disappear upon hide * #466 Alert not shown after Biometry check * #465 Fix broken Carthage build. The Carthage build was broken due to the `iMessageDemo` project's use of CocoaPods and the automatically generated `SwiftMessages` framework scheme created by CocoaPods. The podfile was modified to delete this scheme, but Carthage users may need to run `pod install` on the `iMessagesDemo` project, if they have CocoaPods installed, or manually delete the `iMessageDemo/Pods/Pods.xcodeproj/xcuserdata` folder. From 8cd41df1290aa6f40665eb98aaeb06f59ff3d594 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Tue, 29 Jun 2021 11:29:52 -0500 Subject: [PATCH 106/139] Some minor cleanup --- SwiftMessages/Animator.swift | 4 ++-- SwiftMessages/TopBottomAnimation.swift | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SwiftMessages/Animator.swift b/SwiftMessages/Animator.swift index 7d924e2d..82074068 100644 --- a/SwiftMessages/Animator.swift +++ b/SwiftMessages/Animator.swift @@ -10,7 +10,7 @@ import UIKit public typealias AnimationCompletion = (_ completed: Bool) -> Void -public protocol AnimationDelegate: class { +public protocol AnimationDelegate: AnyObject { func hide(animator: Animator) func panStarted(animator: Animator) func panEnded(animator: Animator) @@ -58,7 +58,7 @@ public class AnimationContext { } } -public protocol Animator: class { +public protocol Animator: AnyObject { /// Adopting classes should declare as `weak`. var delegate: AnimationDelegate? { get set } diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index d9f1f3a4..21b0f271 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -19,17 +19,17 @@ public class TopBottomAnimation: NSObject, Animator { public let style: Style - open var showDuration: TimeInterval = 0.4 + public var showDuration: TimeInterval = 0.4 - open var hideDuration: TimeInterval = 0.2 + public var hideDuration: TimeInterval = 0.2 - open var springDamping: CGFloat = 0.8 + public var springDamping: CGFloat = 0.8 - open var closeSpeedThreshold: CGFloat = 750.0; + public var closeSpeedThreshold: CGFloat = 750.0; - open var closePercentThreshold: CGFloat = 0.33; + public var closePercentThreshold: CGFloat = 0.33; - open var closeAbsoluteThreshold: CGFloat = 75.0; + public var closeAbsoluteThreshold: CGFloat = 75.0; public private(set) lazy var panGestureRecognizer: UIPanGestureRecognizer = { let pan = UIPanGestureRecognizer() From 349fec7674f588d7c32b2aa0c55dfe46eb9f071b Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Tue, 29 Jun 2021 13:48:32 -0500 Subject: [PATCH 107/139] Fix warning --- SwiftMessages/KeyboardTrackingView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages/KeyboardTrackingView.swift b/SwiftMessages/KeyboardTrackingView.swift index 69ce6b0b..6af384a6 100644 --- a/SwiftMessages/KeyboardTrackingView.swift +++ b/SwiftMessages/KeyboardTrackingView.swift @@ -8,7 +8,7 @@ import UIKit -public protocol KeyboardTrackingViewDelegate: class { +public protocol KeyboardTrackingViewDelegate: AnyObject { func keyboardTrackingViewWillChange(change: KeyboardTrackingView.Change, userInfo: [AnyHashable : Any]) func keyboardTrackingViewDidChange(change: KeyboardTrackingView.Change, userInfo: [AnyHashable : Any]) } From c5026484ff555db961ec549162e4026b017aa6c5 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Fri, 17 Sep 2021 16:42:06 -0500 Subject: [PATCH 108/139] Work/9.0.4 (#479) * Add dark mode theme * Remove availability check, which is not supported in iOS 15 * Support Xcode 13 (#478) * Remove @available from enum cases * Carthage support * Refactor * Remove unnecessary methods * Code review Co-authored-by: Timothy Moose * Prep for release * Update changelog Co-authored-by: Kohki Miki --- CHANGELOG.md | 5 + SwiftMessages.podspec | 2 +- SwiftMessages.xcodeproj/project.pbxproj | 10 +- SwiftMessages/MessageView.swift | 72 +- .../SwiftMessages.Config+Extensions.swift | 2 +- SwiftMessages/SwiftMessages.swift | 17 +- SwiftMessages/WindowScene.swift | 9 + iMessageDemo/Podfile.lock | 2 +- iMessageDemo/Pods/Manifest.lock | 2 +- .../Pods/Pods.xcodeproj/project.pbxproj | 900 +++++++++--------- 10 files changed, 550 insertions(+), 471 deletions(-) create mode 100644 SwiftMessages/WindowScene.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index d44911cf..ed087150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.4 + +* #471 Xcode 13 issue - Enum cases with associated values cannot be marked potentially unavailable with '@available' +* Improve colors for dark mode. + ## 9.0.3 ### Fixes diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index a6c018fa..688f100f 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.3' + spec.version = '9.0.4' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 5103fcdd..b01d9c2f 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0797E40E26EE12B400691606 /* WindowScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0797E40D26EE12B400691606 /* WindowScene.swift */; }; 220655121FAF82B600F4E00F /* MarginAdjustable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 220655111FAF82B600F4E00F /* MarginAdjustable+Extensions.swift */; }; 220D386E2597AA5B00BB2B88 /* SwiftMessages.Config+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 220D386D2597AA5B00BB2B88 /* SwiftMessages.Config+Extensions.swift */; }; 224FB69921153B440081D4DE /* CALayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 224FB69821153B440081D4DE /* CALayer+Extensions.swift */; }; @@ -54,7 +55,7 @@ 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; - 229F778125FAB1E9008C2ACB /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */; }; + 229F778125FAB1E9008C2ACB /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */; }; 22DFC9161EFF30F6001B1CA1 /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */; }; 22DFC9181F00674E001B1CA1 /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */; }; 22E01F641E74EC8B00ACE19A /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22E01F631E74EC8B00ACE19A /* MaskingView.swift */; }; @@ -94,6 +95,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0797E40D26EE12B400691606 /* WindowScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowScene.swift; sourceTree = ""; }; 220655111FAF82B600F4E00F /* MarginAdjustable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MarginAdjustable+Extensions.swift"; sourceTree = ""; }; 220D386D2597AA5B00BB2B88 /* SwiftMessages.Config+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftMessages.Config+Extensions.swift"; sourceTree = ""; }; 224FB69821153B440081D4DE /* CALayer+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+Extensions.swift"; sourceTree = ""; }; @@ -141,7 +143,7 @@ 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; - 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Extensions.swift"; sourceTree = ""; }; + 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Extensions.swift"; sourceTree = ""; }; 22A2EA6E24EC6CFA00BB2540 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CenteredView.xib; path = Resources/CenteredView.xib; sourceTree = ""; }; 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsPanHandler.swift; sourceTree = ""; }; @@ -211,7 +213,7 @@ children = ( 220655111FAF82B600F4E00F /* MarginAdjustable+Extensions.swift */, 22774B9F20B5EF2A00813732 /* UIEdgeInsets+Extensions.swift */, - 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */, + 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */, ); name = Extensions; sourceTree = ""; @@ -304,6 +306,7 @@ 2298C2041EE47DC900E2DDC1 /* Weak.swift */, 22F27950210CE25900273E7F /* CornerRoundingView.swift */, 225304652293000C00A03ACF /* KeyboardTrackingView.swift */, + 0797E40D26EE12B400691606 /* WindowScene.swift */, ); name = Base; sourceTree = ""; @@ -555,6 +558,7 @@ 86BBA9081D5E040C00FE8F16 /* Error.swift in Sources */, 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */, 86589D471D64B6E40041676C /* BaseView.swift in Sources */, + 0797E40E26EE12B400691606 /* WindowScene.swift in Sources */, 225304622290C76E00A03ACF /* NSLayoutConstraint+Extensions.swift in Sources */, 86BBA9071D5E040C00FE8F16 /* MarginAdjustable.swift in Sources */, 867BED211D622793005212E3 /* BackgroundViewable.swift in Sources */, diff --git a/SwiftMessages/MessageView.swift b/SwiftMessages/MessageView.swift index d9be31d9..c71141a6 100644 --- a/SwiftMessages/MessageView.swift +++ b/SwiftMessages/MessageView.swift @@ -251,24 +251,72 @@ extension MessageView { */ public func configureTheme(_ theme: Theme, iconStyle: IconStyle = .default) { let iconImage = iconStyle.image(theme: theme) + let backgroundColor: UIColor + let foregroundColor: UIColor + let defaultBackgroundColor: UIColor + let defaultForegroundColor: UIColor switch theme { case .info: - let backgroundColor = UIColor(red: 225.0/255.0, green: 225.0/255.0, blue: 225.0/255.0, alpha: 1.0) - let foregroundColor = UIColor.darkText - configureTheme(backgroundColor: backgroundColor, foregroundColor: foregroundColor, iconImage: iconImage) + defaultBackgroundColor = UIColor(red: 225.0/255.0, green: 225.0/255.0, blue: 225.0/255.0, alpha: 1.0) + defaultForegroundColor = UIColor.darkText case .success: - let backgroundColor = UIColor(red: 97.0/255.0, green: 161.0/255.0, blue: 23.0/255.0, alpha: 1.0) - let foregroundColor = UIColor.white - configureTheme(backgroundColor: backgroundColor, foregroundColor: foregroundColor, iconImage: iconImage) + defaultBackgroundColor = UIColor(red: 97.0/255.0, green: 161.0/255.0, blue: 23.0/255.0, alpha: 1.0) + defaultForegroundColor = UIColor.white case .warning: - let backgroundColor = UIColor(red: 238.0/255.0, green: 189.0/255.0, blue: 34.0/255.0, alpha: 1.0) - let foregroundColor = UIColor.white - configureTheme(backgroundColor: backgroundColor, foregroundColor: foregroundColor, iconImage: iconImage) + defaultBackgroundColor = UIColor(red: 246.0/255.0, green: 197.0/255.0, blue: 44.0/255.0, alpha: 1.0) + defaultForegroundColor = UIColor.white case .error: - let backgroundColor = UIColor(red: 249.0/255.0, green: 66.0/255.0, blue: 47.0/255.0, alpha: 1.0) - let foregroundColor = UIColor.white - configureTheme(backgroundColor: backgroundColor, foregroundColor: foregroundColor, iconImage: iconImage) + defaultBackgroundColor = UIColor(red: 249.0/255.0, green: 66.0/255.0, blue: 47.0/255.0, alpha: 1.0) + defaultForegroundColor = UIColor.white } + if #available(iOS 13.0, *) { + switch theme { + case .info: + backgroundColor = UIColor { + switch $0.userInterfaceStyle { + case .dark, .unspecified: return UIColor(red: 125/255.0, green: 125/255.0, blue: 125/255.0, alpha: 1.0) + case .light: fallthrough + @unknown default: + return defaultBackgroundColor + } + } + foregroundColor = .label + case .success: + backgroundColor = UIColor { + switch $0.userInterfaceStyle { + case .dark, .unspecified: return UIColor(red: 55/255.0, green: 122/255.0, blue: 0/255.0, alpha: 1.0) + case .light: fallthrough + @unknown default: + return defaultBackgroundColor + } + } + foregroundColor = .white + case .warning: + backgroundColor = UIColor { + switch $0.userInterfaceStyle { + case .dark, .unspecified: return UIColor(red: 239/255.0, green: 184/255.0, blue: 10/255.0, alpha: 1.0) + case .light: fallthrough + @unknown default: + return defaultBackgroundColor + } + } + foregroundColor = .white + case .error: + backgroundColor = UIColor { + switch $0.userInterfaceStyle { + case .dark, .unspecified: return UIColor(red: 195/255.0, green: 12/255.0, blue: 12/255.0, alpha: 1.0) + case .light: fallthrough + @unknown default: + return defaultBackgroundColor + } + } + foregroundColor = .white + } + } else { + backgroundColor = defaultBackgroundColor + foregroundColor = defaultForegroundColor + } + configureTheme(backgroundColor: backgroundColor, foregroundColor: foregroundColor, iconImage: iconImage) } /** diff --git a/SwiftMessages/SwiftMessages.Config+Extensions.swift b/SwiftMessages/SwiftMessages.Config+Extensions.swift index 9682b5b9..ac0475da 100644 --- a/SwiftMessages/SwiftMessages.Config+Extensions.swift +++ b/SwiftMessages/SwiftMessages.Config+Extensions.swift @@ -20,7 +20,7 @@ extension SwiftMessages.Config { @available (iOS 13.0, *) var windowScene: UIWindowScene? { switch presentationContext { - case .windowScene(let scene, _): return scene + case .windowScene(let scene, _): return scene as? UIWindowScene default: #if SWIFTMESSAGES_APP_EXTENSIONS return nil diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index dfae859c..7c0042f5 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -77,10 +77,10 @@ open class SwiftMessages { of any message view that adopts the `MarginInsetting` protocol (as `MessageView` does) to account for the status bar. As of iOS 13, windows can no longer cover the status bar. The only alternative is to set `Config.prefersStatusBarHidden = true` - to hide it. + to hide it. The `WindowScene` protocol works around the change in Xcode 13 that prevents + using `@availability` attribute with `enum` cases containing associated values. */ - @available(iOS 13.0, *) - case windowScene(_: UIWindowScene, windowLevel: UIWindow.Level) + case windowScene(_: WindowScene, windowLevel: UIWindow.Level) /** Displays the message view under navigation bars and tab bars if an @@ -248,7 +248,16 @@ open class SwiftMessages { Specifies how the container for presenting the message view is selected. The default is `.Automatic`. */ - public var presentationContext = PresentationContext.automatic + public var presentationContext = PresentationContext.automatic { + didSet { + if case .windowScene = presentationContext { + guard #available(iOS 13.0, *) else { + assertionFailure("windowScene is not supported below iOS 13.0.") + return + } + } + } + } /** Specifies the duration of the message view's time on screen before it is diff --git a/SwiftMessages/WindowScene.swift b/SwiftMessages/WindowScene.swift new file mode 100644 index 00000000..a3bbb4ca --- /dev/null +++ b/SwiftMessages/WindowScene.swift @@ -0,0 +1,9 @@ +import Foundation +import UIKit + +/// A workaround for the change in Xcode 13 that prevents using `@availability` attribute +/// with `enum` cases containing associated values. +public protocol WindowScene {} + +@available(iOS 13.0, *) +extension UIWindowScene: WindowScene {} diff --git a/iMessageDemo/Podfile.lock b/iMessageDemo/Podfile.lock index 54bd951e..7162a91f 100644 --- a/iMessageDemo/Podfile.lock +++ b/iMessageDemo/Podfile.lock @@ -13,4 +13,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 2eb9a33592d0c52131c37a9dd169a8c4604ffd7b -COCOAPODS: 1.10.0 +COCOAPODS: 1.10.1 diff --git a/iMessageDemo/Pods/Manifest.lock b/iMessageDemo/Pods/Manifest.lock index 54bd951e..7162a91f 100644 --- a/iMessageDemo/Pods/Manifest.lock +++ b/iMessageDemo/Pods/Manifest.lock @@ -13,4 +13,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 2eb9a33592d0c52131c37a9dd169a8c4604ffd7b -COCOAPODS: 1.10.0 +COCOAPODS: 1.10.1 diff --git a/iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj b/iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj index 468092a5..0d6bbc21 100644 --- a/iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj +++ b/iMessageDemo/Pods/Pods.xcodeproj/project.pbxproj @@ -7,106 +7,107 @@ objects = { /* Begin PBXBuildFile section */ - 00468531530F8A70E3D83622BD482026 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E6941E59EF0D89949E3DF3D89488430 /* Weak.swift */; }; - 0303F738260F2C9BAE20B79DE84E82BC /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2337E6D5F621F3CE9A1E3761984EBE87 /* PhysicsPanHandler.swift */; }; - 0B42A04122166EAD384BCE37FD450FAF /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8901520225CE89F44E6DE88688F29C10 /* MessageView.swift */; }; - 0CE00BF7FB0F6376D89B0AFF1CFD7510 /* PassthroughView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C557E1DC95AFA417E94ED01301F9F2 /* PassthroughView.swift */; }; - 0E7AE1B3CE2734B39ACCE812B4320B44 /* MarginAdjustable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B91AD9D9E743D17D553D48103BE27C46 /* MarginAdjustable+Extensions.swift */; }; - 138A7742F76993FB9EE3555FD2808562 /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = A80433B71162112A79043CB64261DB51 /* successIconLight.png */; }; - 16047C447B00FAA7F42764EC4167C33B /* NSLayoutConstraint+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0970322A5DD8B4A8373C35ED051DE156 /* NSLayoutConstraint+Extensions.swift */; }; - 1F4159921A25C7B2A0E9C587387D829C /* errorIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1B04615682E8B787C964824435BC6616 /* errorIconLight@2x.png */; }; - 1F6162906845BE72A5BCDAF14D6E14B9 /* warningIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 4512DEEA328AB0AAA95D77C84C89E02C /* warningIconSubtle.png */; }; - 2181E713FC7C00EE871FDA6CB62C7E8C /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5607E285A85AC7163B0B8FD447FD27E /* Theme.swift */; }; - 2558CABB502ED605BC21DCFC55A9C0B7 /* MessageView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AE62AA801971C530345349D18AFCCB82 /* MessageView.xib */; }; - 2B23A9DFDAACFE9C0AD5EB6899E63475 /* infoIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4FE466AC4123CDAE9FDA9FCF4FB9CC60 /* infoIconSubtle@2x.png */; }; - 33785D52B8888C2EA02BD0495408E352 /* successIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 72A865FFBAE49EF66A35CB9D709E8D7E /* successIconLight@3x.png */; }; - 3505AB28DBFA49FBE5C8250F3E067E60 /* KeyboardTrackingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536660614870EA0E051BF6BDDF495798 /* KeyboardTrackingView.swift */; }; - 365594AAFDD4EE947EB33E6E86A8578E /* errorIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = A850F76D7E3FEDC20FFB877454069171 /* errorIconSubtle.png */; }; - 425F2D4CE95436680D77C263FF15221B /* SwiftMessages_SwiftMessages.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BEBF018059B0DFCAC8494ABD1C578AD9 /* SwiftMessages_SwiftMessages.bundle */; }; - 4267FACE20717FF3F51C2ACAB8C395A4 /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D0E8B0020635F606875DD02735C502 /* BaseView.swift */; }; - 44150A4B5B2D251FCBB6CA07DC9872B5 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 267E35F9851AAE50DFB8FA0DCA7F2980 /* Animator.swift */; }; - 447E8A096C1ABD2E0AC9674E65A827E3 /* warningIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 0259757860B26C6072E2640B84EC6D45 /* warningIcon.png */; }; - 44C0F194D748EE88027414A5B2094E9B /* successIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C8155ED78358FA5CF39089176FBDE501 /* successIcon@3x.png */; }; - 461760E2818D72B948B60B4835E7B1ED /* NSBundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCF161BD9F1C2CAAFBCADE5E59BD3FD /* NSBundle+Extensions.swift */; }; - 462CDC24C5C8DD6905C4112B6B4BD2ED /* successIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = FC73E6C784AF6CA1F956F57F82ED2803 /* successIcon.png */; }; + 00764FFD14D83F4ABEC0D4D53D48080A /* SwiftMessages-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C6E00017F9E79F6D4926E9CB43A66DF /* SwiftMessages-dummy.m */; }; + 02905CCF79B22A773CD0BA32EDB9648A /* AccessibleMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0201BC51C7CA061016B619400691A139 /* AccessibleMessage.swift */; }; + 05D9CBEC9488BAA2962B174703D25218 /* PassthroughWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A331C2E0BE2AE2118D65AA1F12519F2 /* PassthroughWindow.swift */; }; + 0C55441C4B8356AC1244EED7684E1783 /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D69BE188B82D84ED23AC4E27BAB61D /* MaskingView.swift */; }; + 11DE7052A0A78D6E27D8D129D413DAF6 /* errorIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 7100245A2722BD53D5B3927ED649069F /* errorIconLight.png */; }; + 13620BA62A66C8C6F9345341BCD111ED /* KeyboardTrackingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90AC342C6F09BF7715D4FB95512DD68A /* KeyboardTrackingView.swift */; }; + 1662CF43016AFC375200E466F130D90E /* warningIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 860D833A7A1B108A89ED34AD74778AC0 /* warningIconSubtle.png */; }; + 28F2E02536C48A4B661D6D8AAFB5D37E /* CornerRoundingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 007ACA6F89C6C856F78352A086F3B8EA /* CornerRoundingView.swift */; }; + 30D023ABC2D1CFC829CF04360768B7F8 /* StatusLine.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1E2FE4DB6869F330F19A3A5459AAFFFB /* StatusLine.xib */; }; + 34CB62900FA4AAC84745C7E958657648 /* errorIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D30B2BF71F9D2C63C2D202C99827CDC1 /* errorIconLight@2x.png */; }; + 3A8B97D9210D1E2BEED5E1159BE7E748 /* warningIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = C56AB83FDAB8D6A1328E7EECCAD99A69 /* warningIconLight.png */; }; + 3BFC9F0FAF0757A2D3574ED4E4100D57 /* CALayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 467EAD44C7F625F384822180F004E64F /* CALayer+Extensions.swift */; }; + 4256FC87C833154DCDEE84CD98F910D7 /* Identifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFD31968BF9DF7A9E25A136DF254F3A9 /* Identifiable.swift */; }; 46CCA4DDFDBBDD2A9426BB96C08E4255 /* Pods-iMessageExtensionDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F40CA14AD738DD186B4DA8FD14AE5BD /* Pods-iMessageExtensionDemo-dummy.m */; }; - 492F085489FCAB0EEBE74B098F7D3F4D /* StatusLine.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7A6801849037A728E9BC50E06CE8AD2F /* StatusLine.xib */; }; - 4C78ED4E1780F5609E25CE03429C1DE4 /* errorIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 848251807107C20960A3DABAB27F7475 /* errorIconLight@3x.png */; }; - 4DB5D1FB08693DDDC32BCF19CC1B1AA0 /* warningIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 874D31DE863C88B1D699E1EBFBE0641B /* warningIconLight@2x.png */; }; - 4E703B2A80C64CF1142872BE31263940 /* errorIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 0892E032AE12339D1AD84BDCC78A3C07 /* errorIconLight.png */; }; - 4E9CCFC43646B6CDBE3B787AB09A0147 /* CardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 42F1E753E61B6EDED3908AC66994649C /* CardView.xib */; }; - 5260BD3289BAC54A20457099C4A57EFF /* errorIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 9D1FEAC04417D847EDC10783E054988F /* errorIcon.png */; }; - 52F4ED7F78829270B2AFE5EDBA9EEE2F /* UIEdgeInsets+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A13E69643D651322647C28E3F9E9C9 /* UIEdgeInsets+Extensions.swift */; }; + 47F1E9964F1112D0E8F0FF8C25204E2F /* SwiftMessages_SwiftMessages.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BEBF018059B0DFCAC8494ABD1C578AD9 /* SwiftMessages_SwiftMessages.bundle */; }; + 4889E21A2024267A944084FB851200B5 /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7EE64CFE0084CF5213A03AF29A668ED /* BaseView.swift */; }; + 4B907B48F27F55DF65CC1553C7C26942 /* infoIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 730840765E737D45772EBE66DB8A6D2E /* infoIconLight.png */; }; + 4B9459A11E2A1D65AE3224CF468AE8CA /* warningIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7C4DF53A4B44C246968618BF25962786 /* warningIconLight@3x.png */; }; + 4E82DE4069FECF20D0E29CB06A0FCFB6 /* SwiftMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6264350B8D100D5B5C5EEEC316933D /* SwiftMessages.swift */; }; + 531825CE7041C5C1BA684BDA9C8972A3 /* UIEdgeInsets+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F7B24601DF4C00B14EC8CE2D4A48DC /* UIEdgeInsets+Extensions.swift */; }; 560A2B1056FEFE42AC6524A2A1742CA2 /* Pods-iMessageExtensionDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAB201AD00CAB811B045E2FFB5C03A8 /* Pods-iMessageExtensionDemo-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 57072960EA4F0D307171ED90697D3FAF /* TabView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B7FD0618783A3E6B90D3A3323633959F /* TabView.xib */; }; - 5720D965B3CE67653082137053FBEC9C /* infoIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C110C924ED12D2D32ECC27503018A31 /* infoIconLight.png */; }; - 5750C24C3A9CAE11C7E36B37434912D0 /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CF61FDEFE095F0486E9914F2262ADB9 /* MaskingView.swift */; }; - 5DF3F4808ED4A6932839C11A5D742B93 /* successIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 54B278C80D821C120FA70ABB6CAF1F46 /* successIconSubtle@3x.png */; }; - 6320AE79D41E8D1F52AF66A670542561 /* CornerRoundingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F8D7902822221456B697BB41111E450 /* CornerRoundingView.swift */; }; - 64595C731B826EB19E9757D524E0BF76 /* warningIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CFBBC25592C97C925B6F81B53BE57CB /* warningIcon@3x.png */; }; - 683A7897D1E9A73F4717198B1C054D29 /* errorIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 60268FE48AA4DC9FD5060B1E5CE68453 /* errorIcon@2x.png */; }; - 6A539682FDDA0E5DA23E1B5F2BA133C1 /* errorIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6DEAADC09FEB1A8D5B90108103EE478 /* errorIcon@3x.png */; }; - 6C7DAA6A68AFDACD67F2C127CEF4DD6F /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C8F928170138667B9326F9655D75D /* UIWindow+Extensions.swift */; }; - 755DA479621A9D2BB8B84540DE648A7A /* warningIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 667DECE93ABCC6869A071FFEB0F83EA5 /* warningIconSubtle@3x.png */; }; - 7ACCA07CCFD868899D61F4B4AE5774DB /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2B7213B7DC5432DA2B272F25E17AA364 /* infoIconSubtle@3x.png */; }; + 56F9865D99C4FADB8FC83CA548F82110 /* successIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17ADABD24F805C5F7FF62167E7ABEF0A /* successIconSubtle@3x.png */; }; + 5B9F8D117AF7BEDDB511EF475FA25995 /* infoIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 48DC3BADDA3A20F2AEB8585117DAFA0D /* infoIcon@3x.png */; }; + 5CA294C8D3BBC986CF0703D4E2A28687 /* SwiftMessages.Config+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A16E25077F8D76288BE678E6AC1C884 /* SwiftMessages.Config+Extensions.swift */; }; + 61548914728141D77F87E31B3911CE7E /* successIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 91D9224F29E092950BADC27C979E10CC /* successIconSubtle@2x.png */; }; + 62B05E0AC13A614A2F8D8A1BE9B514B3 /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = F9CDB54E629D60FF881DF27B949F4C2D /* infoIconSubtle.png */; }; + 632538BAE98BBFD6CED58844B7611C24 /* MarginAdjustable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C8214A441D845A4A4DD6570FD5D458F /* MarginAdjustable+Extensions.swift */; }; + 6685298EC64F73060F5DB1A841375069 /* warningIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8AD355ED684A939F2A4E333F95E8AC31 /* warningIconSubtle@2x.png */; }; + 668EDAB86421216BEF7D3F932851A834 /* errorIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 468D9889455DE51BD5BBC2360BDBB877 /* errorIconSubtle@2x.png */; }; + 6A933CC66558A1FB0AB0BC76F9807E71 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF65ECDAFAD03A79B5571C6F66D8F35 /* TopBottomAnimation.swift */; }; + 755898E0E511FC5AE881403BEF2A02FC /* successIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D032FCFAE6607CF878AA2F35EF93146C /* successIcon@3x.png */; }; + 7905F28CF56E06626475EBA3EB73D905 /* MarginAdjustable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68834C60D0C5EA751E9F12E427C5FFE /* MarginAdjustable.swift */; }; + 7B352022AFCAA5C364E1E2F61290628E /* MessageView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B8A4CCB4B08D2D3BE586212AB4167DC2 /* MessageView.xib */; }; 7BC52E6F0D9D19B05E62E623E53FCE82 /* Pods-iMessageDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D0ECE831FB5E0EE1D68E837671320C7 /* Pods-iMessageDemo-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7E5ADF1F3B6849D5A0DF8E2B9C1861C5 /* PhysicsAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE3BED1799B2F867F5C984C2A051E36A /* PhysicsAnimation.swift */; }; - 8148CD8F2B38FB38B7B9CCC12E93ECFB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */; }; - 89ACEF0F9E524BD21D6C2460FEC375F8 /* warningIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = ED86D7B42F55040DCE162653FB3C7EDB /* warningIconSubtle@2x.png */; }; - 966B9C1EE6B73E430F03D51A4FD26D20 /* MarginAdjustable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C56947CAF8EFCC7858E1E2F1273427 /* MarginAdjustable.swift */; }; - 9CEE0E569456D932AA34329D2038DF98 /* SwiftMessagesSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFFDB7DDC6B6B064B9D12281E2531BFA /* SwiftMessagesSegue.swift */; }; - 9E3D4CA932041E99B6FD56D4E79A726F /* SwiftMessages-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C614EECDDFE644AF0BF7CB16A3D74404 /* SwiftMessages-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9FFE65CB6E825ECAE4838D53E7BA4C06 /* infoIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4412F313361EFEE7A0193533A5AC5999 /* infoIconLight@3x.png */; }; - A11E7A379B288CCA3AE6785B83FA4316 /* AccessibleMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDDAF8A2C45FDDDFD5AFA59203137551 /* AccessibleMessage.swift */; }; - A1734DB0A8A558B2397AF54E63F64416 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8341EF04E2B20C2BF6D4AF2240F80A56 /* Error.swift */; }; + 80DE92140CF5AFB5224643FA952EFDEA /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 52F1CA85E0EED7D94FE0036BC92EB3EC /* successIconLight.png */; }; + 8F1BAB73C85D58C56F55E91573C2E7EF /* infoIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = E41BFEB1BFF85793C0DB85F95184B752 /* infoIcon.png */; }; + 926907C8DCE76101AF5CB470DB7797D7 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D73E42D996B226222A4EBA46F7DC6D /* Weak.swift */; }; + 934A8FA91D6518CB70273B73F8038ECA /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 778F6E19CE49B8EDBAC2FCCD8195A55B /* MessageView.swift */; }; + 946185C05E253C9E47ABCD9EDE7E14D1 /* warningIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 29A39558830996C4F54686A1748B74B1 /* warningIcon@2x.png */; }; + 94B459D6CBA2A01D2B8174D138C30920 /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753B78926D6BB175E96AB6E6F3514E87 /* UIWindow+Extensions.swift */; }; + 95DD12BBA763163407787AB32AAF8E56 /* successIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = A342E145FED9CD8DB4F464D110203E7C /* successIcon.png */; }; + 9B1E91097B4BD539EBCBBCC3C62CB75A /* errorIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = DEC0A6AE07C3285CA508F8FA3F4FE27D /* errorIcon.png */; }; + 9B1F7A4183F57B0AA9DD02624BD8855B /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDEF50CAF615897F7A8540579B445634 /* PhysicsPanHandler.swift */; }; + 9B89868BA12CC4E1D9F116F663E56695 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24021DCE87BE9746D1DFB436C0A3AF7A /* Theme.swift */; }; + 9CFE7FFD7DDE28FCDA72647F2DB82837 /* infoIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 45844D489A130BA91E91E7CDD4969862 /* infoIconSubtle@2x.png */; }; + 9DA2F2EED5C99045AF44FF410A012F9D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */; }; + 9DBD1955C7C621D9DCBE03D2161C91A9 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D261B7BE0088C26BF6744F27B894492A /* UIViewController+Extensions.swift */; }; + 9F0473806FD530165403E47E834790C2 /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 787EE6DA4FBC3BF85ED2CF0BB6EBF494 /* CenteredView.xib */; }; + 9FA48348FB5F41070356A75237367D6D /* TabView.xib in Resources */ = {isa = PBXBuildFile; fileRef = EABF0CEB87991D02E13306975A8E80BB /* TabView.xib */; }; + A67A9ADFBCB364FCEF1BD92FF20B285C /* CardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 705B5AF043D00B6538599B4EB1ECD77C /* CardView.xib */; }; A9EB0C8E49AB748B05CF7941ACAF8475 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */; }; - AC4F13F50EB63B484292D67692BC1F9D /* successIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 1DC54BB09EFDFEDE11F484FE73BEDC60 /* successIconSubtle.png */; }; - B2862C6DDAA6543BB2C8F4541F044564 /* SwiftMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3216CF40D770C387D45C3B4AF2CC9E0 /* SwiftMessages.swift */; }; - B2CC8FF0F9FF3FE929180CDB32B69F18 /* infoIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F7004673F1B51EEC365B32F0E060E564 /* infoIcon@2x.png */; }; - B42A7A38C8014DBDE2632B909F71C355 /* successIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 62755A788F910CA88887B6F63BBC545F /* successIcon@2x.png */; }; - B60094A8D1343B7351F0EF9C51F2F0DB /* infoIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 337B3108412E3812254B85BCC4F90EB8 /* infoIcon@3x.png */; }; - BB16D1E73A5D6B27DC4212926986107F /* warningIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BFEF746702215C33B51BEE64C4E48F0A /* warningIcon@2x.png */; }; - BBFE3BAFFCE67F4EACE0C67A7B7FFC3A /* successIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0B3A169D83BDA3613A661845D1607FC0 /* successIconSubtle@2x.png */; }; - BC4618CE535404A9540D4D110B5767A1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 396FCF260E9C2B3F11080A91E3D72334 /* TopBottomAnimation.swift */; }; - BDCF9C5E4F88B2B0AB6D4595E5A281E1 /* successIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F898B2AC5C3404C266BBCA3B6D22B5E4 /* successIconLight@2x.png */; }; + A9FFA668A7F81F50FBDCDCE26E891C8B /* errorIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = E0E4D99C4F78B9BA011D83FE63EE0946 /* errorIcon@3x.png */; }; + AC0A9B473B11FFF4BDEC0A0598795843 /* WindowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9AA0E820F1C1AA219C066370332845A /* WindowViewController.swift */; }; + AD7F228AE0628DAAE4497493335D2BF7 /* SwiftMessages-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CBEAC9D0EF4113C3FD3B15F511A92D0 /* SwiftMessages-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ADA044C43E517C5F0603B2A0AFB19860 /* successIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 760BFB41B33B6ED91B3FFD68D39083A0 /* successIconLight@2x.png */; }; + ADA91E8F5FDCD2EEC3D3B18A5B375C2C /* errorIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DF3DE135AB5C5C789CABAECC704CE907 /* errorIcon@2x.png */; }; + ADE48B746D5BB28EC33B403E1E12E0FE /* infoIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E936107A7CF9821DCBFFAF50D916F1E6 /* infoIcon@2x.png */; }; + AF34F903519AF36E07A90EF1BD703777 /* WindowScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8DEFE9675E5359A46A443182F127F06 /* WindowScene.swift */; }; + B02B2EAB7B8662AA27D91403BF9AAF36 /* warningIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = A0EE84E98A10805A2D64B836C465ED11 /* warningIconSubtle@3x.png */; }; + B4D338F85183163DC8CAB8A5864C9015 /* infoIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 676F359BE8561CF7512DB8B42CD7873A /* infoIconLight@3x.png */; }; + B520EDE98BD17CE5676F52A77139A933 /* NSLayoutConstraint+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6924EB5FC7236837637AE8F409000A /* NSLayoutConstraint+Extensions.swift */; }; + B679ED0F79CAF552C081588F3B63B91A /* warningIcon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0038C9A582787F9882258E8D1080EACF /* warningIcon@3x.png */; }; + C11CE75FD2DFCDF3B72D8D16280A2054 /* successIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 79D34B3C6875DA0279CB934C84CD000B /* successIcon@2x.png */; }; C384FB76A48C06F7581D0F7850F2F4F1 /* Pods-iMessageDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 14BF989232A1D55A0FDAAB70B5A8E1BF /* Pods-iMessageDemo-dummy.m */; }; C3CDAED707B153A58674CB1AC4A33FB2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */; }; - C4598A458697C49C961BFDCD090B3A8F /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 06F2F626BE8417F1806CC5B17F210C90 /* infoIconSubtle.png */; }; - C5FFE932D5EBE2CC8F2ABFEA893D8E9C /* infoIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 70E7AB099F856140EF93D5B94A967418 /* infoIcon.png */; }; - C6E73F201545CF5ED055C69CD4DB2EFF /* warningIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C17CFEF9B761A322945F74D86CA88036 /* warningIconLight@3x.png */; }; - C8F46E0A5853739D3F632B4828FDE9CC /* PassthroughWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382E6375390EBB09F829519F8ACCB7D7 /* PassthroughWindow.swift */; }; - CCF5CC8F6022DFD410DDCC99A90D58B0 /* warningIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 79E38069364BC5DF4EA88F352E28B242 /* warningIconLight.png */; }; - D49E06426C51C49E9058371138972A69 /* CALayer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B5EF40CEC1F6DB23F428DC159D4BC2 /* CALayer+Extensions.swift */; }; - D61D59BCDFD2C3C7993CFE883DE60692 /* infoIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6516EE9BFCB9C53C151359F9D0247562 /* infoIconLight@2x.png */; }; - D8BDC20F1566606BF64001B6E96B14B6 /* errorIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 453BC098B6A052020C40DE576F684C7B /* errorIconSubtle@3x.png */; }; - D9077478C2FCD7C3DD1EBE9373281728 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C4C88778A19C193D1EC77FA77BAE4C /* UIViewController+Extensions.swift */; }; - E88597F65A00A5AF50EEF2ABA2392B2F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D245E0514AAC1A2B9A6D5EA2F383E90F /* UIKit.framework */; }; - E94E8711BDDA31B178AA032D3346C307 /* BackgroundViewable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAB58A9F688DD39112E6CDF20C8969C0 /* BackgroundViewable.swift */; }; - EDA146BF3FF59593677F8B2AA785D8A5 /* errorIconSubtle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3C313FB1D33EF4B477FD5D3D6179A8BE /* errorIconSubtle@2x.png */; }; - F27E3EEAFDDAA6CB4E7407D6A46DAA5D /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3DF091E68C4659506DB08B0876BD274C /* CenteredView.xib */; }; - F50FE2EE47422AD39AC8F7F115081E7E /* SwiftMessages.Config+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C32E945AE3E6394EF85CD6BEC714B4 /* SwiftMessages.Config+Extensions.swift */; }; - F5642C087197B9033252FF10FBA92B59 /* WindowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8566413BFA3FE6827E63E30515C9B3 /* WindowViewController.swift */; }; - FA6CA270F521DF68A75E527954A2DDAD /* SwiftMessages-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A2F9031B7FA82A17F04D4403091DF836 /* SwiftMessages-dummy.m */; }; - FCB6832EB4D32EF085E770E8B4A9BC2C /* Identifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0DE01AB7D0935933E7AFBDF2945814 /* Identifiable.swift */; }; - FF01BC94FADD5A72282AEE043DF523A7 /* Presenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A965DD26246DCA8CE39FBAB348ABA24 /* Presenter.swift */; }; + C418A50F3C321227B0C6BE1D793680D4 /* successIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA199E6F18AB8900B5400EBA0EB32765 /* successIconLight@3x.png */; }; + C739607C022819840C267A0B4A7B2FD9 /* SwiftMessagesSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF27E3EF103BACDEE8CA842B2C90C8CA /* SwiftMessagesSegue.swift */; }; + C826D41BE5AF283B12C122AEF9640C99 /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C9F5DBB6D77B1E61E9BB1A722A4E1823 /* infoIconSubtle@3x.png */; }; + CC9369D0A5F8715733A4D517E45A3B63 /* infoIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8315EA451FE61625920FEF68174A0D22 /* infoIconLight@2x.png */; }; + CD480EEF400EC9B894F3292506BF0179 /* successIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = B031268635405AA009D05130C0FC253C /* successIconSubtle.png */; }; + D34D8255545B84A38C98D2DBB2F12CC5 /* PassthroughView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E03CBB908F2EC39AA5DA7AF04E1BDDD6 /* PassthroughView.swift */; }; + DE23509CED3A1E62F60E7E4BD6D38A35 /* BackgroundViewable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C706F1F1C6B3CE84445485C8577D5388 /* BackgroundViewable.swift */; }; + DECF1F62709D95EF5B48628A97B3CF98 /* warningIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 3259F99D03B6D738D7F47A625E7BD3BE /* warningIcon.png */; }; + E70A6E572A6DD457A766908E3ADCF49B /* errorIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = C787DA4E67B952C984FF5B065E0A2FF7 /* errorIconSubtle.png */; }; + E8174481BFB4559462F82062D85C0376 /* warningIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFB0D50D01FFFA3FC2099E395029AE68 /* warningIconLight@2x.png */; }; + ECE268E9A63198F53B3F0337B3EA8AF3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D245E0514AAC1A2B9A6D5EA2F383E90F /* UIKit.framework */; }; + F05B5437AFF475FE8811E2A8A734920F /* NSBundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E2EB968B30DE56F38B5FCFFEDE9F88F /* NSBundle+Extensions.swift */; }; + F4BE83FBD5001DEDF6736E69ADA6D79B /* Presenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F513F2674553CBC247EE4B24EA25C99C /* Presenter.swift */; }; + F69D9D53A5500A42D4B41097537628E5 /* errorIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = E31D045D9E355D4F7F75564026B2051A /* errorIconSubtle@3x.png */; }; + F75A8D3DA9B4787BEEEBF3F784D5CDEF /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D219D80184B8ED97808EE17507B213A /* Animator.swift */; }; + F9A111F30C3B26D0A35B0829EED70D26 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5E610C06F5B006DE57F34D5994532FB /* Error.swift */; }; + FA02B47E32DD9BEAAB8A2D1B66F697D5 /* PhysicsAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D2B448BE319CF56A38E222C0B7DF4CB /* PhysicsAnimation.swift */; }; + FDC2C20416D7EBF959A461E25FAFB16E /* errorIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D34E3F2A49E9024A96334DA4147F27B /* errorIconLight@3x.png */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 141E78A8858DBF8B2695DFEDCBDF5158 /* PBXContainerItemProxy */ = { + 4B785BB517DA1D687C0B772C77660019 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 1FC5E8328653C350899229BDF89FACE5; - remoteInfo = "SwiftMessages-SwiftMessages_SwiftMessages"; + remoteGlobalIDString = DAB613A18652334F6BFC5F27BADF515D; + remoteInfo = SwiftMessages; }; - 4DB1DDB02425E67ED85C70C3B138E205 /* PBXContainerItemProxy */ = { + D19F271ED5B0FED7305E55070B415EDB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = DAB613A18652334F6BFC5F27BADF515D; - remoteInfo = SwiftMessages; + remoteGlobalIDString = 1FC5E8328653C350899229BDF89FACE5; + remoteInfo = "SwiftMessages-SwiftMessages_SwiftMessages"; }; - 900F05D1477FFAB64FF410CBB6B9B74D /* PBXContainerItemProxy */ = { + DA9FA5DB745280F35DD4EFAC9A7A4FD7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; @@ -116,112 +117,113 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 0259757860B26C6072E2640B84EC6D45 /* warningIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIcon.png; path = SwiftMessages/Resources/warningIcon.png; sourceTree = ""; }; - 06F2F626BE8417F1806CC5B17F210C90 /* infoIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIconSubtle.png; path = SwiftMessages/Resources/infoIconSubtle.png; sourceTree = ""; }; - 0892E032AE12339D1AD84BDCC78A3C07 /* errorIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIconLight.png; path = SwiftMessages/Resources/errorIconLight.png; sourceTree = ""; }; + 0038C9A582787F9882258E8D1080EACF /* warningIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIcon@3x.png"; path = "SwiftMessages/Resources/warningIcon@3x.png"; sourceTree = ""; }; + 007ACA6F89C6C856F78352A086F3B8EA /* CornerRoundingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CornerRoundingView.swift; path = SwiftMessages/CornerRoundingView.swift; sourceTree = ""; }; + 0201BC51C7CA061016B619400691A139 /* AccessibleMessage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AccessibleMessage.swift; path = SwiftMessages/AccessibleMessage.swift; sourceTree = ""; }; 093D5BBE2A96A1A7AC0432A3AB933576 /* Pods-iMessageDemo-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageDemo-Info.plist"; sourceTree = ""; }; - 0970322A5DD8B4A8373C35ED051DE156 /* NSLayoutConstraint+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSLayoutConstraint+Extensions.swift"; path = "SwiftMessages/NSLayoutConstraint+Extensions.swift"; sourceTree = ""; }; - 0A8566413BFA3FE6827E63E30515C9B3 /* WindowViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WindowViewController.swift; path = SwiftMessages/WindowViewController.swift; sourceTree = ""; }; - 0B3A169D83BDA3613A661845D1607FC0 /* successIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconSubtle@2x.png"; path = "SwiftMessages/Resources/successIconSubtle@2x.png"; sourceTree = ""; }; + 0AF65ECDAFAD03A79B5571C6F66D8F35 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TopBottomAnimation.swift; path = SwiftMessages/TopBottomAnimation.swift; sourceTree = ""; }; + 0BEC185781E869FB5FDB7F10538230C7 /* SwiftMessages.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SwiftMessages.modulemap; sourceTree = ""; }; + 0D2B448BE319CF56A38E222C0B7DF4CB /* PhysicsAnimation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PhysicsAnimation.swift; path = SwiftMessages/PhysicsAnimation.swift; sourceTree = ""; }; 1341BB7116EC50FDF7062C6A91DEDF49 /* Pods-iMessageExtensionDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageExtensionDemo-acknowledgements.plist"; sourceTree = ""; }; + 141AADF8046C9D5EC8E194DF662BAC41 /* ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist"; sourceTree = ""; }; 14BF989232A1D55A0FDAAB70B5A8E1BF /* Pods-iMessageDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-iMessageDemo-dummy.m"; sourceTree = ""; }; - 15C4C88778A19C193D1EC77FA77BAE4C /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIViewController+Extensions.swift"; path = "SwiftMessages/UIViewController+Extensions.swift"; sourceTree = ""; }; - 19B5EF40CEC1F6DB23F428DC159D4BC2 /* CALayer+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CALayer+Extensions.swift"; path = "SwiftMessages/CALayer+Extensions.swift"; sourceTree = ""; }; - 1B04615682E8B787C964824435BC6616 /* errorIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconLight@2x.png"; path = "SwiftMessages/Resources/errorIconLight@2x.png"; sourceTree = ""; }; - 1DC54BB09EFDFEDE11F484FE73BEDC60 /* successIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIconSubtle.png; path = SwiftMessages/Resources/successIconSubtle.png; sourceTree = ""; }; - 2337E6D5F621F3CE9A1E3761984EBE87 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PhysicsPanHandler.swift; path = SwiftMessages/PhysicsPanHandler.swift; sourceTree = ""; }; - 267E35F9851AAE50DFB8FA0DCA7F2980 /* Animator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Animator.swift; path = SwiftMessages/Animator.swift; sourceTree = ""; }; - 2B6B36CBE6DC07B2F005E30EA2B121CB /* LICENSE.md */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE.md; sourceTree = ""; }; - 2B7213B7DC5432DA2B272F25E17AA364 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "SwiftMessages/Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; - 2CFBBC25592C97C925B6F81B53BE57CB /* warningIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIcon@3x.png"; path = "SwiftMessages/Resources/warningIcon@3x.png"; sourceTree = ""; }; + 17ADABD24F805C5F7FF62167E7ABEF0A /* successIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconSubtle@3x.png"; path = "SwiftMessages/Resources/successIconSubtle@3x.png"; sourceTree = ""; }; + 1A331C2E0BE2AE2118D65AA1F12519F2 /* PassthroughWindow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PassthroughWindow.swift; path = SwiftMessages/PassthroughWindow.swift; sourceTree = ""; }; + 1E2FE4DB6869F330F19A3A5459AAFFFB /* StatusLine.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = StatusLine.xib; path = SwiftMessages/Resources/StatusLine.xib; sourceTree = ""; }; + 1ED635B9451869879B1A404F00C3CCC7 /* SwiftMessages-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftMessages-prefix.pch"; sourceTree = ""; }; + 24021DCE87BE9746D1DFB436C0A3AF7A /* Theme.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Theme.swift; path = SwiftMessages/Theme.swift; sourceTree = ""; }; + 29A39558830996C4F54686A1748B74B1 /* warningIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIcon@2x.png"; path = "SwiftMessages/Resources/warningIcon@2x.png"; sourceTree = ""; }; 2D0ECE831FB5E0EE1D68E837671320C7 /* Pods-iMessageDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-iMessageDemo-umbrella.h"; sourceTree = ""; }; - 2E6941E59EF0D89949E3DF3D89488430 /* Weak.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SwiftMessages/Weak.swift; sourceTree = ""; }; - 337B3108412E3812254B85BCC4F90EB8 /* infoIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIcon@3x.png"; path = "SwiftMessages/Resources/infoIcon@3x.png"; sourceTree = ""; }; - 346718C2C7A108C86535F89FEB0EC176 /* SwiftMessages.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SwiftMessages.modulemap; sourceTree = ""; }; - 382E6375390EBB09F829519F8ACCB7D7 /* PassthroughWindow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PassthroughWindow.swift; path = SwiftMessages/PassthroughWindow.swift; sourceTree = ""; }; - 396FCF260E9C2B3F11080A91E3D72334 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TopBottomAnimation.swift; path = SwiftMessages/TopBottomAnimation.swift; sourceTree = ""; }; - 397C8F928170138667B9326F9655D75D /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIWindow+Extensions.swift"; path = "SwiftMessages/UIWindow+Extensions.swift"; sourceTree = ""; }; - 3C313FB1D33EF4B477FD5D3D6179A8BE /* errorIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconSubtle@2x.png"; path = "SwiftMessages/Resources/errorIconSubtle@2x.png"; sourceTree = ""; }; - 3DF091E68C4659506DB08B0876BD274C /* CenteredView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = CenteredView.xib; path = SwiftMessages/Resources/CenteredView.xib; sourceTree = ""; }; - 42F1E753E61B6EDED3908AC66994649C /* CardView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = CardView.xib; path = SwiftMessages/Resources/CardView.xib; sourceTree = ""; }; - 4412F313361EFEE7A0193533A5AC5999 /* infoIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconLight@3x.png"; path = "SwiftMessages/Resources/infoIconLight@3x.png"; sourceTree = ""; }; - 4512DEEA328AB0AAA95D77C84C89E02C /* warningIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIconSubtle.png; path = SwiftMessages/Resources/warningIconSubtle.png; sourceTree = ""; }; - 453BC098B6A052020C40DE576F684C7B /* errorIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconSubtle@3x.png"; path = "SwiftMessages/Resources/errorIconSubtle@3x.png"; sourceTree = ""; }; + 3259F99D03B6D738D7F47A625E7BD3BE /* warningIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIcon.png; path = SwiftMessages/Resources/warningIcon.png; sourceTree = ""; }; + 36F7B24601DF4C00B14EC8CE2D4A48DC /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIEdgeInsets+Extensions.swift"; path = "SwiftMessages/UIEdgeInsets+Extensions.swift"; sourceTree = ""; }; + 3E2EB968B30DE56F38B5FCFFEDE9F88F /* NSBundle+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSBundle+Extensions.swift"; path = "SwiftMessages/NSBundle+Extensions.swift"; sourceTree = ""; }; + 45844D489A130BA91E91E7CDD4969862 /* infoIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconSubtle@2x.png"; path = "SwiftMessages/Resources/infoIconSubtle@2x.png"; sourceTree = ""; }; + 467EAD44C7F625F384822180F004E64F /* CALayer+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CALayer+Extensions.swift"; path = "SwiftMessages/CALayer+Extensions.swift"; sourceTree = ""; }; + 468D9889455DE51BD5BBC2360BDBB877 /* errorIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconSubtle@2x.png"; path = "SwiftMessages/Resources/errorIconSubtle@2x.png"; sourceTree = ""; }; 4824F23D80FF9070A5F8A452DB11EB9A /* SwiftMessages.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SwiftMessages.framework; path = SwiftMessages.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4F8D7902822221456B697BB41111E450 /* CornerRoundingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CornerRoundingView.swift; path = SwiftMessages/CornerRoundingView.swift; sourceTree = ""; }; - 4FE466AC4123CDAE9FDA9FCF4FB9CC60 /* infoIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconSubtle@2x.png"; path = "SwiftMessages/Resources/infoIconSubtle@2x.png"; sourceTree = ""; }; - 536660614870EA0E051BF6BDDF495798 /* KeyboardTrackingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyboardTrackingView.swift; path = SwiftMessages/KeyboardTrackingView.swift; sourceTree = ""; }; - 54B278C80D821C120FA70ABB6CAF1F46 /* successIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconSubtle@3x.png"; path = "SwiftMessages/Resources/successIconSubtle@3x.png"; sourceTree = ""; }; - 5C0DE01AB7D0935933E7AFBDF2945814 /* Identifiable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Identifiable.swift; path = SwiftMessages/Identifiable.swift; sourceTree = ""; }; + 48DC3BADDA3A20F2AEB8585117DAFA0D /* infoIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIcon@3x.png"; path = "SwiftMessages/Resources/infoIcon@3x.png"; sourceTree = ""; }; + 4D34E3F2A49E9024A96334DA4147F27B /* errorIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconLight@3x.png"; path = "SwiftMessages/Resources/errorIconLight@3x.png"; sourceTree = ""; }; + 52F1CA85E0EED7D94FE0036BC92EB3EC /* successIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIconLight.png; path = SwiftMessages/Resources/successIconLight.png; sourceTree = ""; }; + 59FEAC25BE3FCB9F8373DE26400CC89D /* SwiftMessages.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = SwiftMessages.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 5A16E25077F8D76288BE678E6AC1C884 /* SwiftMessages.Config+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SwiftMessages.Config+Extensions.swift"; path = "SwiftMessages/SwiftMessages.Config+Extensions.swift"; sourceTree = ""; }; 5CAB201AD00CAB811B045E2FFB5C03A8 /* Pods-iMessageExtensionDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-iMessageExtensionDemo-umbrella.h"; sourceTree = ""; }; - 60268FE48AA4DC9FD5060B1E5CE68453 /* errorIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIcon@2x.png"; path = "SwiftMessages/Resources/errorIcon@2x.png"; sourceTree = ""; }; - 62755A788F910CA88887B6F63BBC545F /* successIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIcon@2x.png"; path = "SwiftMessages/Resources/successIcon@2x.png"; sourceTree = ""; }; 6489B2A759075E9DC1D1406734F45B5F /* Pods-iMessageExtensionDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-iMessageExtensionDemo.modulemap"; sourceTree = ""; }; - 6516EE9BFCB9C53C151359F9D0247562 /* infoIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconLight@2x.png"; path = "SwiftMessages/Resources/infoIconLight@2x.png"; sourceTree = ""; }; - 667DECE93ABCC6869A071FFEB0F83EA5 /* warningIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconSubtle@3x.png"; path = "SwiftMessages/Resources/warningIconSubtle@3x.png"; sourceTree = ""; }; - 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftMessages.debug.xcconfig; sourceTree = ""; }; - 70E7AB099F856140EF93D5B94A967418 /* infoIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIcon.png; path = SwiftMessages/Resources/infoIcon.png; sourceTree = ""; }; - 7241B2130D211F0832CCE4928CBB6486 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; path = README.md; sourceTree = ""; }; - 72A865FFBAE49EF66A35CB9D709E8D7E /* successIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconLight@3x.png"; path = "SwiftMessages/Resources/successIconLight@3x.png"; sourceTree = ""; }; - 79E38069364BC5DF4EA88F352E28B242 /* warningIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIconLight.png; path = SwiftMessages/Resources/warningIconLight.png; sourceTree = ""; }; - 7A6801849037A728E9BC50E06CE8AD2F /* StatusLine.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = StatusLine.xib; path = SwiftMessages/Resources/StatusLine.xib; sourceTree = ""; }; - 7A965DD26246DCA8CE39FBAB348ABA24 /* Presenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Presenter.swift; path = SwiftMessages/Presenter.swift; sourceTree = ""; }; + 676F359BE8561CF7512DB8B42CD7873A /* infoIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconLight@3x.png"; path = "SwiftMessages/Resources/infoIconLight@3x.png"; sourceTree = ""; }; + 705B5AF043D00B6538599B4EB1ECD77C /* CardView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = CardView.xib; path = SwiftMessages/Resources/CardView.xib; sourceTree = ""; }; + 7100245A2722BD53D5B3927ED649069F /* errorIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIconLight.png; path = SwiftMessages/Resources/errorIconLight.png; sourceTree = ""; }; + 730840765E737D45772EBE66DB8A6D2E /* infoIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIconLight.png; path = SwiftMessages/Resources/infoIconLight.png; sourceTree = ""; }; + 74C53DDA65E08AD7274EA6625408AB99 /* SwiftMessages-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SwiftMessages-Info.plist"; sourceTree = ""; }; + 753B78926D6BB175E96AB6E6F3514E87 /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIWindow+Extensions.swift"; path = "SwiftMessages/UIWindow+Extensions.swift"; sourceTree = ""; }; + 760BFB41B33B6ED91B3FFD68D39083A0 /* successIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconLight@2x.png"; path = "SwiftMessages/Resources/successIconLight@2x.png"; sourceTree = ""; }; + 778F6E19CE49B8EDBAC2FCCD8195A55B /* MessageView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MessageView.swift; path = SwiftMessages/MessageView.swift; sourceTree = ""; }; + 787EE6DA4FBC3BF85ED2CF0BB6EBF494 /* CenteredView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = CenteredView.xib; path = SwiftMessages/Resources/CenteredView.xib; sourceTree = ""; }; + 79D34B3C6875DA0279CB934C84CD000B /* successIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIcon@2x.png"; path = "SwiftMessages/Resources/successIcon@2x.png"; sourceTree = ""; }; + 7C4DF53A4B44C246968618BF25962786 /* warningIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconLight@3x.png"; path = "SwiftMessages/Resources/warningIconLight@3x.png"; sourceTree = ""; }; + 7C8214A441D845A4A4DD6570FD5D458F /* MarginAdjustable+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "MarginAdjustable+Extensions.swift"; path = "SwiftMessages/MarginAdjustable+Extensions.swift"; sourceTree = ""; }; 7CC6A596A9C1659D8E93222DA4144414 /* Pods-iMessageExtensionDemo-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageExtensionDemo-Info.plist"; sourceTree = ""; }; 7F40CA14AD738DD186B4DA8FD14AE5BD /* Pods-iMessageExtensionDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-iMessageExtensionDemo-dummy.m"; sourceTree = ""; }; - 7FCF161BD9F1C2CAAFBCADE5E59BD3FD /* NSBundle+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSBundle+Extensions.swift"; path = "SwiftMessages/NSBundle+Extensions.swift"; sourceTree = ""; }; 820B743874F7AC9F9E3970D68E2E60FA /* Pods-iMessageDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageDemo.release.xcconfig"; sourceTree = ""; }; - 8341EF04E2B20C2BF6D4AF2240F80A56 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = SwiftMessages/Error.swift; sourceTree = ""; }; - 848251807107C20960A3DABAB27F7475 /* errorIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconLight@3x.png"; path = "SwiftMessages/Resources/errorIconLight@3x.png"; sourceTree = ""; }; - 874D31DE863C88B1D699E1EBFBE0641B /* warningIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconLight@2x.png"; path = "SwiftMessages/Resources/warningIconLight@2x.png"; sourceTree = ""; }; - 8901520225CE89F44E6DE88688F29C10 /* MessageView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MessageView.swift; path = SwiftMessages/MessageView.swift; sourceTree = ""; }; + 8315EA451FE61625920FEF68174A0D22 /* infoIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconLight@2x.png"; path = "SwiftMessages/Resources/infoIconLight@2x.png"; sourceTree = ""; }; + 860D833A7A1B108A89ED34AD74778AC0 /* warningIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIconSubtle.png; path = SwiftMessages/Resources/warningIconSubtle.png; sourceTree = ""; }; + 87745BF2C7154EF88509BED0D71243F1 /* SwiftMessages.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftMessages.debug.xcconfig; sourceTree = ""; }; + 88D73E42D996B226222A4EBA46F7DC6D /* Weak.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SwiftMessages/Weak.swift; sourceTree = ""; }; + 8AD355ED684A939F2A4E333F95E8AC31 /* warningIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconSubtle@2x.png"; path = "SwiftMessages/Resources/warningIconSubtle@2x.png"; sourceTree = ""; }; + 8D219D80184B8ED97808EE17507B213A /* Animator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Animator.swift; path = SwiftMessages/Animator.swift; sourceTree = ""; }; 8D54691037F1CA4653B76F0558E2AA82 /* Pods-iMessageExtensionDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-iMessageExtensionDemo-acknowledgements.markdown"; sourceTree = ""; }; - 90F364E0C9A6EFE24680868D0BD293F1 /* SwiftMessages-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SwiftMessages-Info.plist"; sourceTree = ""; }; + 90AC342C6F09BF7715D4FB95512DD68A /* KeyboardTrackingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyboardTrackingView.swift; path = SwiftMessages/KeyboardTrackingView.swift; sourceTree = ""; }; 915DE2E4E300BAD440BE13F72E49D731 /* Pods-iMessageDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iMessageDemo-acknowledgements.plist"; sourceTree = ""; }; - 9C110C924ED12D2D32ECC27503018A31 /* infoIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIconLight.png; path = SwiftMessages/Resources/infoIconLight.png; sourceTree = ""; }; - 9CF61FDEFE095F0486E9914F2262ADB9 /* MaskingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MaskingView.swift; path = SwiftMessages/MaskingView.swift; sourceTree = ""; }; - 9D1FEAC04417D847EDC10783E054988F /* errorIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIcon.png; path = SwiftMessages/Resources/errorIcon.png; sourceTree = ""; }; + 91D9224F29E092950BADC27C979E10CC /* successIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconSubtle@2x.png"; path = "SwiftMessages/Resources/successIconSubtle@2x.png"; sourceTree = ""; }; + 9C6E00017F9E79F6D4926E9CB43A66DF /* SwiftMessages-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SwiftMessages-dummy.m"; sourceTree = ""; }; + 9CBEAC9D0EF4113C3FD3B15F511A92D0 /* SwiftMessages-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftMessages-umbrella.h"; sourceTree = ""; }; 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - A0D0E8B0020635F606875DD02735C502 /* BaseView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BaseView.swift; path = SwiftMessages/BaseView.swift; sourceTree = ""; }; - A2F9031B7FA82A17F04D4403091DF836 /* SwiftMessages-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SwiftMessages-dummy.m"; sourceTree = ""; }; - A3C32E945AE3E6394EF85CD6BEC714B4 /* SwiftMessages.Config+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SwiftMessages.Config+Extensions.swift"; path = "SwiftMessages/SwiftMessages.Config+Extensions.swift"; sourceTree = ""; }; - A80433B71162112A79043CB64261DB51 /* successIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIconLight.png; path = SwiftMessages/Resources/successIconLight.png; sourceTree = ""; }; - A850F76D7E3FEDC20FFB877454069171 /* errorIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIconSubtle.png; path = SwiftMessages/Resources/errorIconSubtle.png; sourceTree = ""; }; - A9A13E69643D651322647C28E3F9E9C9 /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIEdgeInsets+Extensions.swift"; path = "SwiftMessages/UIEdgeInsets+Extensions.swift"; sourceTree = ""; }; - AE62AA801971C530345349D18AFCCB82 /* MessageView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = MessageView.xib; path = SwiftMessages/Resources/MessageView.xib; sourceTree = ""; }; + A0EE84E98A10805A2D64B836C465ED11 /* warningIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconSubtle@3x.png"; path = "SwiftMessages/Resources/warningIconSubtle@3x.png"; sourceTree = ""; }; + A342E145FED9CD8DB4F464D110203E7C /* successIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIcon.png; path = SwiftMessages/Resources/successIcon.png; sourceTree = ""; }; AE7AEA9CE6B44DCC96AE4E68FA644DAA /* Pods-iMessageExtensionDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageExtensionDemo.release.xcconfig"; sourceTree = ""; }; AFC41396FB1BD59C9A69EE1DD82E47C2 /* Pods_iMessageDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_iMessageDemo.framework; path = "Pods-iMessageDemo.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; - AFFDB7DDC6B6B064B9D12281E2531BFA /* SwiftMessagesSegue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftMessagesSegue.swift; path = SwiftMessages/SwiftMessagesSegue.swift; sourceTree = ""; }; - B6DEAADC09FEB1A8D5B90108103EE478 /* errorIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIcon@3x.png"; path = "SwiftMessages/Resources/errorIcon@3x.png"; sourceTree = ""; }; - B7FD0618783A3E6B90D3A3323633959F /* TabView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = TabView.xib; path = SwiftMessages/Resources/TabView.xib; sourceTree = ""; }; - B91AD9D9E743D17D553D48103BE27C46 /* MarginAdjustable+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "MarginAdjustable+Extensions.swift"; path = "SwiftMessages/MarginAdjustable+Extensions.swift"; sourceTree = ""; }; + B031268635405AA009D05130C0FC253C /* successIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIconSubtle.png; path = SwiftMessages/Resources/successIconSubtle.png; sourceTree = ""; }; + B7BF853CD0CDFA20423D4C813B34B57F /* SwiftMessages.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftMessages.release.xcconfig; sourceTree = ""; }; + B8A4CCB4B08D2D3BE586212AB4167DC2 /* MessageView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = MessageView.xib; path = SwiftMessages/Resources/MessageView.xib; sourceTree = ""; }; B99CBDE49D6502CF64EB9059C005BF31 /* Pods-iMessageDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageDemo.debug.xcconfig"; sourceTree = ""; }; + BDEF50CAF615897F7A8540579B445634 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PhysicsPanHandler.swift; path = SwiftMessages/PhysicsPanHandler.swift; sourceTree = ""; }; BEBF018059B0DFCAC8494ABD1C578AD9 /* SwiftMessages_SwiftMessages.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = SwiftMessages_SwiftMessages.bundle; path = "SwiftMessages-SwiftMessages_SwiftMessages.bundle"; sourceTree = BUILT_PRODUCTS_DIR; }; + BF27E3EF103BACDEE8CA842B2C90C8CA /* SwiftMessagesSegue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftMessagesSegue.swift; path = SwiftMessages/SwiftMessagesSegue.swift; sourceTree = ""; }; BF61E78F8E8EE539F4A63C5A9D43AC15 /* Pods-iMessageDemo-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-iMessageDemo-frameworks.sh"; sourceTree = ""; }; - BFEF746702215C33B51BEE64C4E48F0A /* warningIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIcon@2x.png"; path = "SwiftMessages/Resources/warningIcon@2x.png"; sourceTree = ""; }; - C17CFEF9B761A322945F74D86CA88036 /* warningIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconLight@3x.png"; path = "SwiftMessages/Resources/warningIconLight@3x.png"; sourceTree = ""; }; C306ACAFEE157959D78E71DBBBD675DC /* Pods-iMessageExtensionDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iMessageExtensionDemo.debug.xcconfig"; sourceTree = ""; }; - C3216CF40D770C387D45C3B4AF2CC9E0 /* SwiftMessages.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftMessages.swift; path = SwiftMessages/SwiftMessages.swift; sourceTree = ""; }; - C614EECDDFE644AF0BF7CB16A3D74404 /* SwiftMessages-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftMessages-umbrella.h"; sourceTree = ""; }; - C6C56947CAF8EFCC7858E1E2F1273427 /* MarginAdjustable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MarginAdjustable.swift; path = SwiftMessages/MarginAdjustable.swift; sourceTree = ""; }; - C7FE39695CB7C6997ACA39C8680B414A /* SwiftMessages.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = SwiftMessages.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - C8155ED78358FA5CF39089176FBDE501 /* successIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIcon@3x.png"; path = "SwiftMessages/Resources/successIcon@3x.png"; sourceTree = ""; }; - C9D915B60769D3C45A0DA3A5BA9514B8 /* ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist"; sourceTree = ""; }; - CAB58A9F688DD39112E6CDF20C8969C0 /* BackgroundViewable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BackgroundViewable.swift; path = SwiftMessages/BackgroundViewable.swift; sourceTree = ""; }; + C56AB83FDAB8D6A1328E7EECCAD99A69 /* warningIconLight.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = warningIconLight.png; path = SwiftMessages/Resources/warningIconLight.png; sourceTree = ""; }; + C5E610C06F5B006DE57F34D5994532FB /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = SwiftMessages/Error.swift; sourceTree = ""; }; + C706F1F1C6B3CE84445485C8577D5388 /* BackgroundViewable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BackgroundViewable.swift; path = SwiftMessages/BackgroundViewable.swift; sourceTree = ""; }; + C787DA4E67B952C984FF5B065E0A2FF7 /* errorIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIconSubtle.png; path = SwiftMessages/Resources/errorIconSubtle.png; sourceTree = ""; }; + C7EE64CFE0084CF5213A03AF29A668ED /* BaseView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BaseView.swift; path = SwiftMessages/BaseView.swift; sourceTree = ""; }; + C9F5DBB6D77B1E61E9BB1A722A4E1823 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "SwiftMessages/Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; CBC3F501D8BC852716D085B3022E68CA /* Pods_iMessageExtensionDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_iMessageExtensionDemo.framework; path = "Pods-iMessageExtensionDemo.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; CC9152C843976F18EF9AE005786DCC80 /* Pods-iMessageDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-iMessageDemo.modulemap"; sourceTree = ""; }; + D032FCFAE6607CF878AA2F35EF93146C /* successIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIcon@3x.png"; path = "SwiftMessages/Resources/successIcon@3x.png"; sourceTree = ""; }; + D1D69BE188B82D84ED23AC4E27BAB61D /* MaskingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MaskingView.swift; path = SwiftMessages/MaskingView.swift; sourceTree = ""; }; D245E0514AAC1A2B9A6D5EA2F383E90F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; - D5607E285A85AC7163B0B8FD447FD27E /* Theme.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Theme.swift; path = SwiftMessages/Theme.swift; sourceTree = ""; }; - D7C557E1DC95AFA417E94ED01301F9F2 /* PassthroughView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PassthroughView.swift; path = SwiftMessages/PassthroughView.swift; sourceTree = ""; }; - E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftMessages.release.xcconfig; sourceTree = ""; }; + D261B7BE0088C26BF6744F27B894492A /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIViewController+Extensions.swift"; path = "SwiftMessages/UIViewController+Extensions.swift"; sourceTree = ""; }; + D30B2BF71F9D2C63C2D202C99827CDC1 /* errorIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconLight@2x.png"; path = "SwiftMessages/Resources/errorIconLight@2x.png"; sourceTree = ""; }; + D68834C60D0C5EA751E9F12E427C5FFE /* MarginAdjustable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MarginAdjustable.swift; path = SwiftMessages/MarginAdjustable.swift; sourceTree = ""; }; + D8DEFE9675E5359A46A443182F127F06 /* WindowScene.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WindowScene.swift; path = SwiftMessages/WindowScene.swift; sourceTree = ""; }; + D9AA0E820F1C1AA219C066370332845A /* WindowViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WindowViewController.swift; path = SwiftMessages/WindowViewController.swift; sourceTree = ""; }; + DB6924EB5FC7236837637AE8F409000A /* NSLayoutConstraint+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSLayoutConstraint+Extensions.swift"; path = "SwiftMessages/NSLayoutConstraint+Extensions.swift"; sourceTree = ""; }; + DEC0A6AE07C3285CA508F8FA3F4FE27D /* errorIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = errorIcon.png; path = SwiftMessages/Resources/errorIcon.png; sourceTree = ""; }; + DF3DE135AB5C5C789CABAECC704CE907 /* errorIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIcon@2x.png"; path = "SwiftMessages/Resources/errorIcon@2x.png"; sourceTree = ""; }; + E03CBB908F2EC39AA5DA7AF04E1BDDD6 /* PassthroughView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PassthroughView.swift; path = SwiftMessages/PassthroughView.swift; sourceTree = ""; }; + E0E4D99C4F78B9BA011D83FE63EE0946 /* errorIcon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIcon@3x.png"; path = "SwiftMessages/Resources/errorIcon@3x.png"; sourceTree = ""; }; + E31D045D9E355D4F7F75564026B2051A /* errorIconSubtle@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "errorIconSubtle@3x.png"; path = "SwiftMessages/Resources/errorIconSubtle@3x.png"; sourceTree = ""; }; + E41BFEB1BFF85793C0DB85F95184B752 /* infoIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIcon.png; path = SwiftMessages/Resources/infoIcon.png; sourceTree = ""; }; E473E4F019E816262A61B7F5E8B42373 /* Pods-iMessageDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-iMessageDemo-acknowledgements.markdown"; sourceTree = ""; }; + E936107A7CF9821DCBFFAF50D916F1E6 /* infoIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIcon@2x.png"; path = "SwiftMessages/Resources/infoIcon@2x.png"; sourceTree = ""; }; + E9E929B0E2A84EA903C9923B926A44E2 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; path = README.md; sourceTree = ""; }; EAB6F611E86A4758835A715E4B4184F6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - ED86D7B42F55040DCE162653FB3C7EDB /* warningIconSubtle@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconSubtle@2x.png"; path = "SwiftMessages/Resources/warningIconSubtle@2x.png"; sourceTree = ""; }; - EDDAF8A2C45FDDDFD5AFA59203137551 /* AccessibleMessage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AccessibleMessage.swift; path = SwiftMessages/AccessibleMessage.swift; sourceTree = ""; }; - F7004673F1B51EEC365B32F0E060E564 /* infoIcon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "infoIcon@2x.png"; path = "SwiftMessages/Resources/infoIcon@2x.png"; sourceTree = ""; }; - F898B2AC5C3404C266BBCA3B6D22B5E4 /* successIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconLight@2x.png"; path = "SwiftMessages/Resources/successIconLight@2x.png"; sourceTree = ""; }; - FC73E6C784AF6CA1F956F57F82ED2803 /* successIcon.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = successIcon.png; path = SwiftMessages/Resources/successIcon.png; sourceTree = ""; }; - FCDC8870EA94B5B1E966D34D2B1FA5FE /* SwiftMessages-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftMessages-prefix.pch"; sourceTree = ""; }; - FE3BED1799B2F867F5C984C2A051E36A /* PhysicsAnimation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PhysicsAnimation.swift; path = SwiftMessages/PhysicsAnimation.swift; sourceTree = ""; }; + EABF0CEB87991D02E13306975A8E80BB /* TabView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = TabView.xib; path = SwiftMessages/Resources/TabView.xib; sourceTree = ""; }; + EC6264350B8D100D5B5C5EEEC316933D /* SwiftMessages.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftMessages.swift; path = SwiftMessages/SwiftMessages.swift; sourceTree = ""; }; + EFD31968BF9DF7A9E25A136DF254F3A9 /* Identifiable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Identifiable.swift; path = SwiftMessages/Identifiable.swift; sourceTree = ""; }; + F513F2674553CBC247EE4B24EA25C99C /* Presenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Presenter.swift; path = SwiftMessages/Presenter.swift; sourceTree = ""; }; + F9CDB54E629D60FF881DF27B949F4C2D /* infoIconSubtle.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = infoIconSubtle.png; path = SwiftMessages/Resources/infoIconSubtle.png; sourceTree = ""; }; + FA199E6F18AB8900B5400EBA0EB32765 /* successIconLight@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "successIconLight@3x.png"; path = "SwiftMessages/Resources/successIconLight@3x.png"; sourceTree = ""; }; + FC12F21544AE9FE6D9E1E2F7730EF7EC /* LICENSE.md */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE.md; sourceTree = ""; }; + FFB0D50D01FFFA3FC2099E395029AE68 /* warningIconLight@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "warningIconLight@2x.png"; path = "SwiftMessages/Resources/warningIconLight@2x.png"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -233,33 +235,112 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - C3AABE927CAF3C6135B4D37CA433F885 /* Frameworks */ = { + 9DEA36BAD403380FF5C38B4F2B4C3AB9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - F2C6C6F4FCF31DEB85ADCA0DE9EF6EEC /* Frameworks */ = { + EF08D4F0B96CF6C9AB42DC368EE3849A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A9EB0C8E49AB748B05CF7941ACAF8475 /* Foundation.framework in Frameworks */, + 9DA2F2EED5C99045AF44FF410A012F9D /* Foundation.framework in Frameworks */, + ECE268E9A63198F53B3F0337B3EA8AF3 /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - FA7AA2A57B110DEF3C1F616FA77A05A7 /* Frameworks */ = { + F2C6C6F4FCF31DEB85ADCA0DE9EF6EEC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8148CD8F2B38FB38B7B9CCC12E93ECFB /* Foundation.framework in Frameworks */, - E88597F65A00A5AF50EEF2ABA2392B2F /* UIKit.framework in Frameworks */, + A9EB0C8E49AB748B05CF7941ACAF8475 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 089392E699971024974E80EFFB25EE61 /* AppExtension */ = { + isa = PBXGroup; + children = ( + 0201BC51C7CA061016B619400691A139 /* AccessibleMessage.swift */, + 8D219D80184B8ED97808EE17507B213A /* Animator.swift */, + C706F1F1C6B3CE84445485C8577D5388 /* BackgroundViewable.swift */, + C7EE64CFE0084CF5213A03AF29A668ED /* BaseView.swift */, + 467EAD44C7F625F384822180F004E64F /* CALayer+Extensions.swift */, + 705B5AF043D00B6538599B4EB1ECD77C /* CardView.xib */, + 787EE6DA4FBC3BF85ED2CF0BB6EBF494 /* CenteredView.xib */, + 007ACA6F89C6C856F78352A086F3B8EA /* CornerRoundingView.swift */, + C5E610C06F5B006DE57F34D5994532FB /* Error.swift */, + DEC0A6AE07C3285CA508F8FA3F4FE27D /* errorIcon.png */, + DF3DE135AB5C5C789CABAECC704CE907 /* errorIcon@2x.png */, + E0E4D99C4F78B9BA011D83FE63EE0946 /* errorIcon@3x.png */, + 7100245A2722BD53D5B3927ED649069F /* errorIconLight.png */, + D30B2BF71F9D2C63C2D202C99827CDC1 /* errorIconLight@2x.png */, + 4D34E3F2A49E9024A96334DA4147F27B /* errorIconLight@3x.png */, + C787DA4E67B952C984FF5B065E0A2FF7 /* errorIconSubtle.png */, + 468D9889455DE51BD5BBC2360BDBB877 /* errorIconSubtle@2x.png */, + E31D045D9E355D4F7F75564026B2051A /* errorIconSubtle@3x.png */, + EFD31968BF9DF7A9E25A136DF254F3A9 /* Identifiable.swift */, + E41BFEB1BFF85793C0DB85F95184B752 /* infoIcon.png */, + E936107A7CF9821DCBFFAF50D916F1E6 /* infoIcon@2x.png */, + 48DC3BADDA3A20F2AEB8585117DAFA0D /* infoIcon@3x.png */, + 730840765E737D45772EBE66DB8A6D2E /* infoIconLight.png */, + 8315EA451FE61625920FEF68174A0D22 /* infoIconLight@2x.png */, + 676F359BE8561CF7512DB8B42CD7873A /* infoIconLight@3x.png */, + F9CDB54E629D60FF881DF27B949F4C2D /* infoIconSubtle.png */, + 45844D489A130BA91E91E7CDD4969862 /* infoIconSubtle@2x.png */, + C9F5DBB6D77B1E61E9BB1A722A4E1823 /* infoIconSubtle@3x.png */, + 90AC342C6F09BF7715D4FB95512DD68A /* KeyboardTrackingView.swift */, + D68834C60D0C5EA751E9F12E427C5FFE /* MarginAdjustable.swift */, + 7C8214A441D845A4A4DD6570FD5D458F /* MarginAdjustable+Extensions.swift */, + D1D69BE188B82D84ED23AC4E27BAB61D /* MaskingView.swift */, + 778F6E19CE49B8EDBAC2FCCD8195A55B /* MessageView.swift */, + B8A4CCB4B08D2D3BE586212AB4167DC2 /* MessageView.xib */, + 3E2EB968B30DE56F38B5FCFFEDE9F88F /* NSBundle+Extensions.swift */, + DB6924EB5FC7236837637AE8F409000A /* NSLayoutConstraint+Extensions.swift */, + E03CBB908F2EC39AA5DA7AF04E1BDDD6 /* PassthroughView.swift */, + 1A331C2E0BE2AE2118D65AA1F12519F2 /* PassthroughWindow.swift */, + 0D2B448BE319CF56A38E222C0B7DF4CB /* PhysicsAnimation.swift */, + BDEF50CAF615897F7A8540579B445634 /* PhysicsPanHandler.swift */, + F513F2674553CBC247EE4B24EA25C99C /* Presenter.swift */, + 1E2FE4DB6869F330F19A3A5459AAFFFB /* StatusLine.xib */, + A342E145FED9CD8DB4F464D110203E7C /* successIcon.png */, + 79D34B3C6875DA0279CB934C84CD000B /* successIcon@2x.png */, + D032FCFAE6607CF878AA2F35EF93146C /* successIcon@3x.png */, + 52F1CA85E0EED7D94FE0036BC92EB3EC /* successIconLight.png */, + 760BFB41B33B6ED91B3FFD68D39083A0 /* successIconLight@2x.png */, + FA199E6F18AB8900B5400EBA0EB32765 /* successIconLight@3x.png */, + B031268635405AA009D05130C0FC253C /* successIconSubtle.png */, + 91D9224F29E092950BADC27C979E10CC /* successIconSubtle@2x.png */, + 17ADABD24F805C5F7FF62167E7ABEF0A /* successIconSubtle@3x.png */, + EC6264350B8D100D5B5C5EEEC316933D /* SwiftMessages.swift */, + 5A16E25077F8D76288BE678E6AC1C884 /* SwiftMessages.Config+Extensions.swift */, + BF27E3EF103BACDEE8CA842B2C90C8CA /* SwiftMessagesSegue.swift */, + EABF0CEB87991D02E13306975A8E80BB /* TabView.xib */, + 24021DCE87BE9746D1DFB436C0A3AF7A /* Theme.swift */, + 0AF65ECDAFAD03A79B5571C6F66D8F35 /* TopBottomAnimation.swift */, + 36F7B24601DF4C00B14EC8CE2D4A48DC /* UIEdgeInsets+Extensions.swift */, + D261B7BE0088C26BF6744F27B894492A /* UIViewController+Extensions.swift */, + 753B78926D6BB175E96AB6E6F3514E87 /* UIWindow+Extensions.swift */, + 3259F99D03B6D738D7F47A625E7BD3BE /* warningIcon.png */, + 29A39558830996C4F54686A1748B74B1 /* warningIcon@2x.png */, + 0038C9A582787F9882258E8D1080EACF /* warningIcon@3x.png */, + C56AB83FDAB8D6A1328E7EECCAD99A69 /* warningIconLight.png */, + FFB0D50D01FFFA3FC2099E395029AE68 /* warningIconLight@2x.png */, + 7C4DF53A4B44C246968618BF25962786 /* warningIconLight@3x.png */, + 860D833A7A1B108A89ED34AD74778AC0 /* warningIconSubtle.png */, + 8AD355ED684A939F2A4E333F95E8AC31 /* warningIconSubtle@2x.png */, + A0EE84E98A10805A2D64B836C465ED11 /* warningIconSubtle@3x.png */, + 88D73E42D996B226222A4EBA46F7DC6D /* Weak.swift */, + D8DEFE9675E5359A46A443182F127F06 /* WindowScene.swift */, + D9AA0E820F1C1AA219C066370332845A /* WindowViewController.swift */, + ); + name = AppExtension; + sourceTree = ""; + }; 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -288,24 +369,40 @@ name = iOS; sourceTree = ""; }; - 8F3CF4AFB0CA47B3BFE1C68E51CDF0A9 /* Targets Support Files */ = { + 5EAB54907DABB41DF2E9177067EF69D4 /* SwiftMessages */ = { isa = PBXGroup; children = ( - 9A912CA1E54EADE1787311C1DF7E8F2E /* Pods-iMessageDemo */, - BD13800F87C70DC802DBC0C37E8C5E99 /* Pods-iMessageExtensionDemo */, + 089392E699971024974E80EFFB25EE61 /* AppExtension */, + E7706B1F04CCC75F42C733B60ED5FBDC /* Pod */, + 7C00C98D65B96C8BDE003F39DAFBBBDE /* Support Files */, ); - name = "Targets Support Files"; + name = SwiftMessages; + path = ../..; sourceTree = ""; }; - 9A632FB0C8554E0688B34926AF9C52DB /* SwiftMessages */ = { + 7C00C98D65B96C8BDE003F39DAFBBBDE /* Support Files */ = { isa = PBXGroup; children = ( - AD776BCEA093D43499821A6E4251BF03 /* AppExtension */, - A58DF9B1678B5C3CCA8A840C72186044 /* Pod */, - B3699CF01F28F4B75166BA983453EAF3 /* Support Files */, + 141AADF8046C9D5EC8E194DF662BAC41 /* ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist */, + 0BEC185781E869FB5FDB7F10538230C7 /* SwiftMessages.modulemap */, + 9C6E00017F9E79F6D4926E9CB43A66DF /* SwiftMessages-dummy.m */, + 74C53DDA65E08AD7274EA6625408AB99 /* SwiftMessages-Info.plist */, + 1ED635B9451869879B1A404F00C3CCC7 /* SwiftMessages-prefix.pch */, + 9CBEAC9D0EF4113C3FD3B15F511A92D0 /* SwiftMessages-umbrella.h */, + 87745BF2C7154EF88509BED0D71243F1 /* SwiftMessages.debug.xcconfig */, + B7BF853CD0CDFA20423D4C813B34B57F /* SwiftMessages.release.xcconfig */, ); - name = SwiftMessages; - path = ../..; + name = "Support Files"; + path = "iMessageDemo/Pods/Target Support Files/SwiftMessages"; + sourceTree = ""; + }; + 8F3CF4AFB0CA47B3BFE1C68E51CDF0A9 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 9A912CA1E54EADE1787311C1DF7E8F2E /* Pods-iMessageDemo */, + BD13800F87C70DC802DBC0C37E8C5E99 /* Pods-iMessageExtensionDemo */, + ); + name = "Targets Support Files"; sourceTree = ""; }; 9A912CA1E54EADE1787311C1DF7E8F2E /* Pods-iMessageDemo */ = { @@ -325,110 +422,6 @@ path = "Target Support Files/Pods-iMessageDemo"; sourceTree = ""; }; - A58DF9B1678B5C3CCA8A840C72186044 /* Pod */ = { - isa = PBXGroup; - children = ( - 2B6B36CBE6DC07B2F005E30EA2B121CB /* LICENSE.md */, - 7241B2130D211F0832CCE4928CBB6486 /* README.md */, - C7FE39695CB7C6997ACA39C8680B414A /* SwiftMessages.podspec */, - ); - name = Pod; - sourceTree = ""; - }; - AD776BCEA093D43499821A6E4251BF03 /* AppExtension */ = { - isa = PBXGroup; - children = ( - EDDAF8A2C45FDDDFD5AFA59203137551 /* AccessibleMessage.swift */, - 267E35F9851AAE50DFB8FA0DCA7F2980 /* Animator.swift */, - CAB58A9F688DD39112E6CDF20C8969C0 /* BackgroundViewable.swift */, - A0D0E8B0020635F606875DD02735C502 /* BaseView.swift */, - 19B5EF40CEC1F6DB23F428DC159D4BC2 /* CALayer+Extensions.swift */, - 42F1E753E61B6EDED3908AC66994649C /* CardView.xib */, - 3DF091E68C4659506DB08B0876BD274C /* CenteredView.xib */, - 4F8D7902822221456B697BB41111E450 /* CornerRoundingView.swift */, - 8341EF04E2B20C2BF6D4AF2240F80A56 /* Error.swift */, - 9D1FEAC04417D847EDC10783E054988F /* errorIcon.png */, - 60268FE48AA4DC9FD5060B1E5CE68453 /* errorIcon@2x.png */, - B6DEAADC09FEB1A8D5B90108103EE478 /* errorIcon@3x.png */, - 0892E032AE12339D1AD84BDCC78A3C07 /* errorIconLight.png */, - 1B04615682E8B787C964824435BC6616 /* errorIconLight@2x.png */, - 848251807107C20960A3DABAB27F7475 /* errorIconLight@3x.png */, - A850F76D7E3FEDC20FFB877454069171 /* errorIconSubtle.png */, - 3C313FB1D33EF4B477FD5D3D6179A8BE /* errorIconSubtle@2x.png */, - 453BC098B6A052020C40DE576F684C7B /* errorIconSubtle@3x.png */, - 5C0DE01AB7D0935933E7AFBDF2945814 /* Identifiable.swift */, - 70E7AB099F856140EF93D5B94A967418 /* infoIcon.png */, - F7004673F1B51EEC365B32F0E060E564 /* infoIcon@2x.png */, - 337B3108412E3812254B85BCC4F90EB8 /* infoIcon@3x.png */, - 9C110C924ED12D2D32ECC27503018A31 /* infoIconLight.png */, - 6516EE9BFCB9C53C151359F9D0247562 /* infoIconLight@2x.png */, - 4412F313361EFEE7A0193533A5AC5999 /* infoIconLight@3x.png */, - 06F2F626BE8417F1806CC5B17F210C90 /* infoIconSubtle.png */, - 4FE466AC4123CDAE9FDA9FCF4FB9CC60 /* infoIconSubtle@2x.png */, - 2B7213B7DC5432DA2B272F25E17AA364 /* infoIconSubtle@3x.png */, - 536660614870EA0E051BF6BDDF495798 /* KeyboardTrackingView.swift */, - C6C56947CAF8EFCC7858E1E2F1273427 /* MarginAdjustable.swift */, - B91AD9D9E743D17D553D48103BE27C46 /* MarginAdjustable+Extensions.swift */, - 9CF61FDEFE095F0486E9914F2262ADB9 /* MaskingView.swift */, - 8901520225CE89F44E6DE88688F29C10 /* MessageView.swift */, - AE62AA801971C530345349D18AFCCB82 /* MessageView.xib */, - 7FCF161BD9F1C2CAAFBCADE5E59BD3FD /* NSBundle+Extensions.swift */, - 0970322A5DD8B4A8373C35ED051DE156 /* NSLayoutConstraint+Extensions.swift */, - D7C557E1DC95AFA417E94ED01301F9F2 /* PassthroughView.swift */, - 382E6375390EBB09F829519F8ACCB7D7 /* PassthroughWindow.swift */, - FE3BED1799B2F867F5C984C2A051E36A /* PhysicsAnimation.swift */, - 2337E6D5F621F3CE9A1E3761984EBE87 /* PhysicsPanHandler.swift */, - 7A965DD26246DCA8CE39FBAB348ABA24 /* Presenter.swift */, - 7A6801849037A728E9BC50E06CE8AD2F /* StatusLine.xib */, - FC73E6C784AF6CA1F956F57F82ED2803 /* successIcon.png */, - 62755A788F910CA88887B6F63BBC545F /* successIcon@2x.png */, - C8155ED78358FA5CF39089176FBDE501 /* successIcon@3x.png */, - A80433B71162112A79043CB64261DB51 /* successIconLight.png */, - F898B2AC5C3404C266BBCA3B6D22B5E4 /* successIconLight@2x.png */, - 72A865FFBAE49EF66A35CB9D709E8D7E /* successIconLight@3x.png */, - 1DC54BB09EFDFEDE11F484FE73BEDC60 /* successIconSubtle.png */, - 0B3A169D83BDA3613A661845D1607FC0 /* successIconSubtle@2x.png */, - 54B278C80D821C120FA70ABB6CAF1F46 /* successIconSubtle@3x.png */, - C3216CF40D770C387D45C3B4AF2CC9E0 /* SwiftMessages.swift */, - A3C32E945AE3E6394EF85CD6BEC714B4 /* SwiftMessages.Config+Extensions.swift */, - AFFDB7DDC6B6B064B9D12281E2531BFA /* SwiftMessagesSegue.swift */, - B7FD0618783A3E6B90D3A3323633959F /* TabView.xib */, - D5607E285A85AC7163B0B8FD447FD27E /* Theme.swift */, - 396FCF260E9C2B3F11080A91E3D72334 /* TopBottomAnimation.swift */, - A9A13E69643D651322647C28E3F9E9C9 /* UIEdgeInsets+Extensions.swift */, - 15C4C88778A19C193D1EC77FA77BAE4C /* UIViewController+Extensions.swift */, - 397C8F928170138667B9326F9655D75D /* UIWindow+Extensions.swift */, - 0259757860B26C6072E2640B84EC6D45 /* warningIcon.png */, - BFEF746702215C33B51BEE64C4E48F0A /* warningIcon@2x.png */, - 2CFBBC25592C97C925B6F81B53BE57CB /* warningIcon@3x.png */, - 79E38069364BC5DF4EA88F352E28B242 /* warningIconLight.png */, - 874D31DE863C88B1D699E1EBFBE0641B /* warningIconLight@2x.png */, - C17CFEF9B761A322945F74D86CA88036 /* warningIconLight@3x.png */, - 4512DEEA328AB0AAA95D77C84C89E02C /* warningIconSubtle.png */, - ED86D7B42F55040DCE162653FB3C7EDB /* warningIconSubtle@2x.png */, - 667DECE93ABCC6869A071FFEB0F83EA5 /* warningIconSubtle@3x.png */, - 2E6941E59EF0D89949E3DF3D89488430 /* Weak.swift */, - 0A8566413BFA3FE6827E63E30515C9B3 /* WindowViewController.swift */, - ); - name = AppExtension; - sourceTree = ""; - }; - B3699CF01F28F4B75166BA983453EAF3 /* Support Files */ = { - isa = PBXGroup; - children = ( - C9D915B60769D3C45A0DA3A5BA9514B8 /* ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist */, - 346718C2C7A108C86535F89FEB0EC176 /* SwiftMessages.modulemap */, - A2F9031B7FA82A17F04D4403091DF836 /* SwiftMessages-dummy.m */, - 90F364E0C9A6EFE24680868D0BD293F1 /* SwiftMessages-Info.plist */, - FCDC8870EA94B5B1E966D34D2B1FA5FE /* SwiftMessages-prefix.pch */, - C614EECDDFE644AF0BF7CB16A3D74404 /* SwiftMessages-umbrella.h */, - 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */, - E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */, - ); - name = "Support Files"; - path = "iMessageDemo/Pods/Target Support Files/SwiftMessages"; - sourceTree = ""; - }; BD13800F87C70DC802DBC0C37E8C5E99 /* Pods-iMessageExtensionDemo */ = { isa = PBXGroup; children = ( @@ -448,7 +441,7 @@ C5AAA95D48373FAC474F6EFCC1749444 /* Development Pods */ = { isa = PBXGroup; children = ( - 9A632FB0C8554E0688B34926AF9C52DB /* SwiftMessages */, + 5EAB54907DABB41DF2E9177067EF69D4 /* SwiftMessages */, ); name = "Development Pods"; sourceTree = ""; @@ -464,30 +457,40 @@ ); sourceTree = ""; }; + E7706B1F04CCC75F42C733B60ED5FBDC /* Pod */ = { + isa = PBXGroup; + children = ( + FC12F21544AE9FE6D9E1E2F7730EF7EC /* LICENSE.md */, + E9E929B0E2A84EA903C9923B926A44E2 /* README.md */, + 59FEAC25BE3FCB9F8373DE26400CC89D /* SwiftMessages.podspec */, + ); + name = Pod; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 96A1C098516CB9F20C4BE19860673FA7 /* Headers */ = { + 21076A86F5547DA5AEE656FE5EC63826 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 560A2B1056FEFE42AC6524A2A1742CA2 /* Pods-iMessageExtensionDemo-umbrella.h in Headers */, + AD7F228AE0628DAAE4497493335D2BF7 /* SwiftMessages-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - AEC231A576EA094C9EF913D75BA2D69C /* Headers */ = { + 96A1C098516CB9F20C4BE19860673FA7 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 7BC52E6F0D9D19B05E62E623E53FCE82 /* Pods-iMessageDemo-umbrella.h in Headers */, + 560A2B1056FEFE42AC6524A2A1742CA2 /* Pods-iMessageExtensionDemo-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - B534C45C1A426DF58D21D75F281F983A /* Headers */ = { + AEC231A576EA094C9EF913D75BA2D69C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 9E3D4CA932041E99B6FD56D4E79A726F /* SwiftMessages-umbrella.h in Headers */, + 7BC52E6F0D9D19B05E62E623E53FCE82 /* Pods-iMessageDemo-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -496,11 +499,11 @@ /* Begin PBXNativeTarget section */ 1FC5E8328653C350899229BDF89FACE5 /* SwiftMessages-SwiftMessages_SwiftMessages */ = { isa = PBXNativeTarget; - buildConfigurationList = 57E1F5473FEF9FC2401E805CCF8188C3 /* Build configuration list for PBXNativeTarget "SwiftMessages-SwiftMessages_SwiftMessages" */; + buildConfigurationList = 1B3FEB13A547A2F656C2328E0CE130B5 /* Build configuration list for PBXNativeTarget "SwiftMessages-SwiftMessages_SwiftMessages" */; buildPhases = ( - 5FA15A9B2968910DC30C1AC895A5397A /* Sources */, - C3AABE927CAF3C6135B4D37CA433F885 /* Frameworks */, - F8808FE568E0B01931D6216DF79110B1 /* Resources */, + FFA9EA2B25A56389D60078D35A7276A6 /* Sources */, + 9DEA36BAD403380FF5C38B4F2B4C3AB9 /* Frameworks */, + BF76892AD99FBDD7554F3F71E205A3B6 /* Resources */, ); buildRules = ( ); @@ -523,7 +526,7 @@ buildRules = ( ); dependencies = ( - BB9BD3F204FD8449B62AD70E23DABC13 /* PBXTargetDependency */, + 4D52C266BAECF408C5DEB677038E1EEA /* PBXTargetDependency */, ); name = "Pods-iMessageExtensionDemo"; productName = "Pods-iMessageExtensionDemo"; @@ -532,17 +535,17 @@ }; DAB613A18652334F6BFC5F27BADF515D /* SwiftMessages */ = { isa = PBXNativeTarget; - buildConfigurationList = ABCC3636B5EAEBE6D60D155704F40EBC /* Build configuration list for PBXNativeTarget "SwiftMessages" */; + buildConfigurationList = 7D9EC6095BF15A96EABE2FE5045DA5DE /* Build configuration list for PBXNativeTarget "SwiftMessages" */; buildPhases = ( - B534C45C1A426DF58D21D75F281F983A /* Headers */, - ABE787B29A89D2BB29F92EAE5C8526CF /* Sources */, - FA7AA2A57B110DEF3C1F616FA77A05A7 /* Frameworks */, - C69D4A2DC76A80BD6D45A9BE85B2EEB1 /* Resources */, + 21076A86F5547DA5AEE656FE5EC63826 /* Headers */, + E0A3D02CDE28535DB4F00412E5814A99 /* Sources */, + EF08D4F0B96CF6C9AB42DC368EE3849A /* Frameworks */, + 036D5B81C59A567C797D02AA3A18D7F4 /* Resources */, ); buildRules = ( ); dependencies = ( - 03EC5F5CF0CAA96E132B778FB51EBCE9 /* PBXTargetDependency */, + 35EE405E4B00027013209FA505020C1C /* PBXTargetDependency */, ); name = SwiftMessages; productName = SwiftMessages; @@ -561,7 +564,7 @@ buildRules = ( ); dependencies = ( - 3CF465B66D2B58FC406E66E621CBCB11 /* PBXTargetDependency */, + 50C0F94C8A0A997FF42A574D8367A3C7 /* PBXTargetDependency */, ); name = "Pods-iMessageDemo"; productName = "Pods-iMessageDemo"; @@ -599,73 +602,73 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 61DB2F41473C1B8FEA6385AA240E2586 /* Resources */ = { + 036D5B81C59A567C797D02AA3A18D7F4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 47F1E9964F1112D0E8F0FF8C25204E2F /* SwiftMessages_SwiftMessages.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - B1A8F08DE3F2C1EF1D63EF29C9D3D327 /* Resources */ = { + 61DB2F41473C1B8FEA6385AA240E2586 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - C69D4A2DC76A80BD6D45A9BE85B2EEB1 /* Resources */ = { + B1A8F08DE3F2C1EF1D63EF29C9D3D327 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 425F2D4CE95436680D77C263FF15221B /* SwiftMessages_SwiftMessages.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - F8808FE568E0B01931D6216DF79110B1 /* Resources */ = { + BF76892AD99FBDD7554F3F71E205A3B6 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4E9CCFC43646B6CDBE3B787AB09A0147 /* CardView.xib in Resources */, - F27E3EEAFDDAA6CB4E7407D6A46DAA5D /* CenteredView.xib in Resources */, - 5260BD3289BAC54A20457099C4A57EFF /* errorIcon.png in Resources */, - 683A7897D1E9A73F4717198B1C054D29 /* errorIcon@2x.png in Resources */, - 6A539682FDDA0E5DA23E1B5F2BA133C1 /* errorIcon@3x.png in Resources */, - 4E703B2A80C64CF1142872BE31263940 /* errorIconLight.png in Resources */, - 1F4159921A25C7B2A0E9C587387D829C /* errorIconLight@2x.png in Resources */, - 4C78ED4E1780F5609E25CE03429C1DE4 /* errorIconLight@3x.png in Resources */, - 365594AAFDD4EE947EB33E6E86A8578E /* errorIconSubtle.png in Resources */, - EDA146BF3FF59593677F8B2AA785D8A5 /* errorIconSubtle@2x.png in Resources */, - D8BDC20F1566606BF64001B6E96B14B6 /* errorIconSubtle@3x.png in Resources */, - C5FFE932D5EBE2CC8F2ABFEA893D8E9C /* infoIcon.png in Resources */, - B2CC8FF0F9FF3FE929180CDB32B69F18 /* infoIcon@2x.png in Resources */, - B60094A8D1343B7351F0EF9C51F2F0DB /* infoIcon@3x.png in Resources */, - 5720D965B3CE67653082137053FBEC9C /* infoIconLight.png in Resources */, - D61D59BCDFD2C3C7993CFE883DE60692 /* infoIconLight@2x.png in Resources */, - 9FFE65CB6E825ECAE4838D53E7BA4C06 /* infoIconLight@3x.png in Resources */, - C4598A458697C49C961BFDCD090B3A8F /* infoIconSubtle.png in Resources */, - 2B23A9DFDAACFE9C0AD5EB6899E63475 /* infoIconSubtle@2x.png in Resources */, - 7ACCA07CCFD868899D61F4B4AE5774DB /* infoIconSubtle@3x.png in Resources */, - 2558CABB502ED605BC21DCFC55A9C0B7 /* MessageView.xib in Resources */, - 492F085489FCAB0EEBE74B098F7D3F4D /* StatusLine.xib in Resources */, - 462CDC24C5C8DD6905C4112B6B4BD2ED /* successIcon.png in Resources */, - B42A7A38C8014DBDE2632B909F71C355 /* successIcon@2x.png in Resources */, - 44C0F194D748EE88027414A5B2094E9B /* successIcon@3x.png in Resources */, - 138A7742F76993FB9EE3555FD2808562 /* successIconLight.png in Resources */, - BDCF9C5E4F88B2B0AB6D4595E5A281E1 /* successIconLight@2x.png in Resources */, - 33785D52B8888C2EA02BD0495408E352 /* successIconLight@3x.png in Resources */, - AC4F13F50EB63B484292D67692BC1F9D /* successIconSubtle.png in Resources */, - BBFE3BAFFCE67F4EACE0C67A7B7FFC3A /* successIconSubtle@2x.png in Resources */, - 5DF3F4808ED4A6932839C11A5D742B93 /* successIconSubtle@3x.png in Resources */, - 57072960EA4F0D307171ED90697D3FAF /* TabView.xib in Resources */, - 447E8A096C1ABD2E0AC9674E65A827E3 /* warningIcon.png in Resources */, - BB16D1E73A5D6B27DC4212926986107F /* warningIcon@2x.png in Resources */, - 64595C731B826EB19E9757D524E0BF76 /* warningIcon@3x.png in Resources */, - CCF5CC8F6022DFD410DDCC99A90D58B0 /* warningIconLight.png in Resources */, - 4DB5D1FB08693DDDC32BCF19CC1B1AA0 /* warningIconLight@2x.png in Resources */, - C6E73F201545CF5ED055C69CD4DB2EFF /* warningIconLight@3x.png in Resources */, - 1F6162906845BE72A5BCDAF14D6E14B9 /* warningIconSubtle.png in Resources */, - 89ACEF0F9E524BD21D6C2460FEC375F8 /* warningIconSubtle@2x.png in Resources */, - 755DA479621A9D2BB8B84540DE648A7A /* warningIconSubtle@3x.png in Resources */, + A67A9ADFBCB364FCEF1BD92FF20B285C /* CardView.xib in Resources */, + 9F0473806FD530165403E47E834790C2 /* CenteredView.xib in Resources */, + 9B1E91097B4BD539EBCBBCC3C62CB75A /* errorIcon.png in Resources */, + ADA91E8F5FDCD2EEC3D3B18A5B375C2C /* errorIcon@2x.png in Resources */, + A9FFA668A7F81F50FBDCDCE26E891C8B /* errorIcon@3x.png in Resources */, + 11DE7052A0A78D6E27D8D129D413DAF6 /* errorIconLight.png in Resources */, + 34CB62900FA4AAC84745C7E958657648 /* errorIconLight@2x.png in Resources */, + FDC2C20416D7EBF959A461E25FAFB16E /* errorIconLight@3x.png in Resources */, + E70A6E572A6DD457A766908E3ADCF49B /* errorIconSubtle.png in Resources */, + 668EDAB86421216BEF7D3F932851A834 /* errorIconSubtle@2x.png in Resources */, + F69D9D53A5500A42D4B41097537628E5 /* errorIconSubtle@3x.png in Resources */, + 8F1BAB73C85D58C56F55E91573C2E7EF /* infoIcon.png in Resources */, + ADE48B746D5BB28EC33B403E1E12E0FE /* infoIcon@2x.png in Resources */, + 5B9F8D117AF7BEDDB511EF475FA25995 /* infoIcon@3x.png in Resources */, + 4B907B48F27F55DF65CC1553C7C26942 /* infoIconLight.png in Resources */, + CC9369D0A5F8715733A4D517E45A3B63 /* infoIconLight@2x.png in Resources */, + B4D338F85183163DC8CAB8A5864C9015 /* infoIconLight@3x.png in Resources */, + 62B05E0AC13A614A2F8D8A1BE9B514B3 /* infoIconSubtle.png in Resources */, + 9CFE7FFD7DDE28FCDA72647F2DB82837 /* infoIconSubtle@2x.png in Resources */, + C826D41BE5AF283B12C122AEF9640C99 /* infoIconSubtle@3x.png in Resources */, + 7B352022AFCAA5C364E1E2F61290628E /* MessageView.xib in Resources */, + 30D023ABC2D1CFC829CF04360768B7F8 /* StatusLine.xib in Resources */, + 95DD12BBA763163407787AB32AAF8E56 /* successIcon.png in Resources */, + C11CE75FD2DFCDF3B72D8D16280A2054 /* successIcon@2x.png in Resources */, + 755898E0E511FC5AE881403BEF2A02FC /* successIcon@3x.png in Resources */, + 80DE92140CF5AFB5224643FA952EFDEA /* successIconLight.png in Resources */, + ADA044C43E517C5F0603B2A0AFB19860 /* successIconLight@2x.png in Resources */, + C418A50F3C321227B0C6BE1D793680D4 /* successIconLight@3x.png in Resources */, + CD480EEF400EC9B894F3292506BF0179 /* successIconSubtle.png in Resources */, + 61548914728141D77F87E31B3911CE7E /* successIconSubtle@2x.png in Resources */, + 56F9865D99C4FADB8FC83CA548F82110 /* successIconSubtle@3x.png in Resources */, + 9FA48348FB5F41070356A75237367D6D /* TabView.xib in Resources */, + DECF1F62709D95EF5B48628A97B3CF98 /* warningIcon.png in Resources */, + 946185C05E253C9E47ABCD9EDE7E14D1 /* warningIcon@2x.png in Resources */, + B679ED0F79CAF552C081588F3B63B91A /* warningIcon@3x.png in Resources */, + 3A8B97D9210D1E2BEED5E1159BE7E748 /* warningIconLight.png in Resources */, + E8174481BFB4559462F82062D85C0376 /* warningIconLight@2x.png in Resources */, + 4B9459A11E2A1D65AE3224CF468AE8CA /* warningIconLight@3x.png in Resources */, + 1662CF43016AFC375200E466F130D90E /* warningIconSubtle.png in Resources */, + 6685298EC64F73060F5DB1A841375069 /* warningIconSubtle@2x.png in Resources */, + B02B2EAB7B8662AA27D91403BF9AAF36 /* warningIconSubtle@3x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -688,78 +691,79 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5FA15A9B2968910DC30C1AC895A5397A /* Sources */ = { + E0A3D02CDE28535DB4F00412E5814A99 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 02905CCF79B22A773CD0BA32EDB9648A /* AccessibleMessage.swift in Sources */, + F75A8D3DA9B4787BEEEBF3F784D5CDEF /* Animator.swift in Sources */, + DE23509CED3A1E62F60E7E4BD6D38A35 /* BackgroundViewable.swift in Sources */, + 4889E21A2024267A944084FB851200B5 /* BaseView.swift in Sources */, + 3BFC9F0FAF0757A2D3574ED4E4100D57 /* CALayer+Extensions.swift in Sources */, + 28F2E02536C48A4B661D6D8AAFB5D37E /* CornerRoundingView.swift in Sources */, + F9A111F30C3B26D0A35B0829EED70D26 /* Error.swift in Sources */, + 4256FC87C833154DCDEE84CD98F910D7 /* Identifiable.swift in Sources */, + 13620BA62A66C8C6F9345341BCD111ED /* KeyboardTrackingView.swift in Sources */, + 632538BAE98BBFD6CED58844B7611C24 /* MarginAdjustable+Extensions.swift in Sources */, + 7905F28CF56E06626475EBA3EB73D905 /* MarginAdjustable.swift in Sources */, + 0C55441C4B8356AC1244EED7684E1783 /* MaskingView.swift in Sources */, + 934A8FA91D6518CB70273B73F8038ECA /* MessageView.swift in Sources */, + F05B5437AFF475FE8811E2A8A734920F /* NSBundle+Extensions.swift in Sources */, + B520EDE98BD17CE5676F52A77139A933 /* NSLayoutConstraint+Extensions.swift in Sources */, + D34D8255545B84A38C98D2DBB2F12CC5 /* PassthroughView.swift in Sources */, + 05D9CBEC9488BAA2962B174703D25218 /* PassthroughWindow.swift in Sources */, + FA02B47E32DD9BEAAB8A2D1B66F697D5 /* PhysicsAnimation.swift in Sources */, + 9B1F7A4183F57B0AA9DD02624BD8855B /* PhysicsPanHandler.swift in Sources */, + F4BE83FBD5001DEDF6736E69ADA6D79B /* Presenter.swift in Sources */, + 00764FFD14D83F4ABEC0D4D53D48080A /* SwiftMessages-dummy.m in Sources */, + 5CA294C8D3BBC986CF0703D4E2A28687 /* SwiftMessages.Config+Extensions.swift in Sources */, + 4E82DE4069FECF20D0E29CB06A0FCFB6 /* SwiftMessages.swift in Sources */, + C739607C022819840C267A0B4A7B2FD9 /* SwiftMessagesSegue.swift in Sources */, + 9B89868BA12CC4E1D9F116F663E56695 /* Theme.swift in Sources */, + 6A933CC66558A1FB0AB0BC76F9807E71 /* TopBottomAnimation.swift in Sources */, + 531825CE7041C5C1BA684BDA9C8972A3 /* UIEdgeInsets+Extensions.swift in Sources */, + 9DBD1955C7C621D9DCBE03D2161C91A9 /* UIViewController+Extensions.swift in Sources */, + 94B459D6CBA2A01D2B8174D138C30920 /* UIWindow+Extensions.swift in Sources */, + 926907C8DCE76101AF5CB470DB7797D7 /* Weak.swift in Sources */, + AF34F903519AF36E07A90EF1BD703777 /* WindowScene.swift in Sources */, + AC0A9B473B11FFF4BDEC0A0598795843 /* WindowViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - ABE787B29A89D2BB29F92EAE5C8526CF /* Sources */ = { + FFA9EA2B25A56389D60078D35A7276A6 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A11E7A379B288CCA3AE6785B83FA4316 /* AccessibleMessage.swift in Sources */, - 44150A4B5B2D251FCBB6CA07DC9872B5 /* Animator.swift in Sources */, - E94E8711BDDA31B178AA032D3346C307 /* BackgroundViewable.swift in Sources */, - 4267FACE20717FF3F51C2ACAB8C395A4 /* BaseView.swift in Sources */, - D49E06426C51C49E9058371138972A69 /* CALayer+Extensions.swift in Sources */, - 6320AE79D41E8D1F52AF66A670542561 /* CornerRoundingView.swift in Sources */, - A1734DB0A8A558B2397AF54E63F64416 /* Error.swift in Sources */, - FCB6832EB4D32EF085E770E8B4A9BC2C /* Identifiable.swift in Sources */, - 3505AB28DBFA49FBE5C8250F3E067E60 /* KeyboardTrackingView.swift in Sources */, - 0E7AE1B3CE2734B39ACCE812B4320B44 /* MarginAdjustable+Extensions.swift in Sources */, - 966B9C1EE6B73E430F03D51A4FD26D20 /* MarginAdjustable.swift in Sources */, - 5750C24C3A9CAE11C7E36B37434912D0 /* MaskingView.swift in Sources */, - 0B42A04122166EAD384BCE37FD450FAF /* MessageView.swift in Sources */, - 461760E2818D72B948B60B4835E7B1ED /* NSBundle+Extensions.swift in Sources */, - 16047C447B00FAA7F42764EC4167C33B /* NSLayoutConstraint+Extensions.swift in Sources */, - 0CE00BF7FB0F6376D89B0AFF1CFD7510 /* PassthroughView.swift in Sources */, - C8F46E0A5853739D3F632B4828FDE9CC /* PassthroughWindow.swift in Sources */, - 7E5ADF1F3B6849D5A0DF8E2B9C1861C5 /* PhysicsAnimation.swift in Sources */, - 0303F738260F2C9BAE20B79DE84E82BC /* PhysicsPanHandler.swift in Sources */, - FF01BC94FADD5A72282AEE043DF523A7 /* Presenter.swift in Sources */, - FA6CA270F521DF68A75E527954A2DDAD /* SwiftMessages-dummy.m in Sources */, - F50FE2EE47422AD39AC8F7F115081E7E /* SwiftMessages.Config+Extensions.swift in Sources */, - B2862C6DDAA6543BB2C8F4541F044564 /* SwiftMessages.swift in Sources */, - 9CEE0E569456D932AA34329D2038DF98 /* SwiftMessagesSegue.swift in Sources */, - 2181E713FC7C00EE871FDA6CB62C7E8C /* Theme.swift in Sources */, - BC4618CE535404A9540D4D110B5767A1 /* TopBottomAnimation.swift in Sources */, - 52F4ED7F78829270B2AFE5EDBA9EEE2F /* UIEdgeInsets+Extensions.swift in Sources */, - D9077478C2FCD7C3DD1EBE9373281728 /* UIViewController+Extensions.swift in Sources */, - 6C7DAA6A68AFDACD67F2C127CEF4DD6F /* UIWindow+Extensions.swift in Sources */, - 00468531530F8A70E3D83622BD482026 /* Weak.swift in Sources */, - F5642C087197B9033252FF10FBA92B59 /* WindowViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 03EC5F5CF0CAA96E132B778FB51EBCE9 /* PBXTargetDependency */ = { + 35EE405E4B00027013209FA505020C1C /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "SwiftMessages-SwiftMessages_SwiftMessages"; target = 1FC5E8328653C350899229BDF89FACE5 /* SwiftMessages-SwiftMessages_SwiftMessages */; - targetProxy = 141E78A8858DBF8B2695DFEDCBDF5158 /* PBXContainerItemProxy */; + targetProxy = D19F271ED5B0FED7305E55070B415EDB /* PBXContainerItemProxy */; }; - 3CF465B66D2B58FC406E66E621CBCB11 /* PBXTargetDependency */ = { + 4D52C266BAECF408C5DEB677038E1EEA /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = SwiftMessages; target = DAB613A18652334F6BFC5F27BADF515D /* SwiftMessages */; - targetProxy = 4DB1DDB02425E67ED85C70C3B138E205 /* PBXContainerItemProxy */; + targetProxy = 4B785BB517DA1D687C0B772C77660019 /* PBXContainerItemProxy */; }; - BB9BD3F204FD8449B62AD70E23DABC13 /* PBXTargetDependency */ = { + 50C0F94C8A0A997FF42A574D8367A3C7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = SwiftMessages; target = DAB613A18652334F6BFC5F27BADF515D /* SwiftMessages */; - targetProxy = 900F05D1477FFAB64FF410CBB6B9B74D /* PBXContainerItemProxy */; + targetProxy = DA9FA5DB745280F35DD4EFAC9A7A4FD7 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 24D1D8F3B822E3083FF435C91CB434FD /* Debug */ = { + 01CE4E62B8DE70DDCEADD46669F1118B /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */; + baseConfigurationReference = 87745BF2C7154EF88509BED0D71243F1 /* SwiftMessages.debug.xcconfig */; buildSettings = { CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/SwiftMessages"; IBSC_MODULE = SwiftMessages; @@ -773,6 +777,22 @@ }; name = Debug; }; + 27EC13F078A5EF4E57265026E5EA01CB /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B7BF853CD0CDFA20423D4C813B34B57F /* SwiftMessages.release.xcconfig */; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/SwiftMessages"; + IBSC_MODULE = SwiftMessages; + INFOPLIST_FILE = "Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = SwiftMessages_SwiftMessages; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; 6427804744C4054555383985007A0B6C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -901,40 +921,6 @@ }; name = Release; }; - 7C5AE2DF0A930DD6AC66390486478632 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/SwiftMessages/SwiftMessages-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/SwiftMessages/SwiftMessages-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULEMAP_FILE = "Target Support Files/SwiftMessages/SwiftMessages.modulemap"; - PRODUCT_MODULE_NAME = SwiftMessages; - PRODUCT_NAME = SwiftMessages; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; 891563622FB1DE05CD4905BE16203F07 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = C306ACAFEE157959D78E71DBBBD675DC /* Pods-iMessageExtensionDemo.debug.xcconfig */; @@ -1010,21 +996,38 @@ }; name = Release; }; - BCFFE899A2E9C1DF0CA120A3F3CECECC /* Release */ = { + B9F08B726D3DD8C6ACDBB8CC2E05B693 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E070773539E02C11297794CC4CB839D6 /* SwiftMessages.release.xcconfig */; + baseConfigurationReference = 87745BF2C7154EF88509BED0D71243F1 /* SwiftMessages.debug.xcconfig */; buildSettings = { - CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/SwiftMessages"; - IBSC_MODULE = SwiftMessages; - INFOPLIST_FILE = "Target Support Files/SwiftMessages/ResourceBundle-SwiftMessages_SwiftMessages-SwiftMessages-Info.plist"; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/SwiftMessages/SwiftMessages-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SwiftMessages/SwiftMessages-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - PRODUCT_NAME = SwiftMessages_SwiftMessages; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/SwiftMessages/SwiftMessages.modulemap"; + PRODUCT_MODULE_NAME = SwiftMessages; + PRODUCT_NAME = SwiftMessages; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - WRAPPER_EXTENSION = bundle; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; - name = Release; + name = Debug; }; C9423D1E13393A1A8BC54BE4E87A96AD /* Release */ = { isa = XCBuildConfiguration; @@ -1064,9 +1067,9 @@ }; name = Release; }; - F069CD2F5774D5082336F140E5F68B3A /* Debug */ = { + D0E16784196812CD6F00BFEE04C50E82 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6E9D4A0FDDEEDDC5A1A63D89B43C1F18 /* SwiftMessages.debug.xcconfig */; + baseConfigurationReference = B7BF853CD0CDFA20423D4C813B34B57F /* SwiftMessages.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -1092,10 +1095,11 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Debug; + name = Release; }; FCA0FCAB93E530D2C6BED8D3910FEB4A /* Debug */ = { isa = XCBuildConfiguration; @@ -1137,38 +1141,38 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 20A82A14E31D7EFF5BE9B60529162F4B /* Build configuration list for PBXNativeTarget "Pods-iMessageDemo" */ = { + 1B3FEB13A547A2F656C2328E0CE130B5 /* Build configuration list for PBXNativeTarget "SwiftMessages-SwiftMessages_SwiftMessages" */ = { isa = XCConfigurationList; buildConfigurations = ( - FCA0FCAB93E530D2C6BED8D3910FEB4A /* Debug */, - C9423D1E13393A1A8BC54BE4E87A96AD /* Release */, + 01CE4E62B8DE70DDCEADD46669F1118B /* Debug */, + 27EC13F078A5EF4E57265026E5EA01CB /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + 20A82A14E31D7EFF5BE9B60529162F4B /* Build configuration list for PBXNativeTarget "Pods-iMessageDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( - 6427804744C4054555383985007A0B6C /* Debug */, - 74556EDEC03158A3009CA84D67369133 /* Release */, + FCA0FCAB93E530D2C6BED8D3910FEB4A /* Debug */, + C9423D1E13393A1A8BC54BE4E87A96AD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 57E1F5473FEF9FC2401E805CCF8188C3 /* Build configuration list for PBXNativeTarget "SwiftMessages-SwiftMessages_SwiftMessages" */ = { + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( - 24D1D8F3B822E3083FF435C91CB434FD /* Debug */, - BCFFE899A2E9C1DF0CA120A3F3CECECC /* Release */, + 6427804744C4054555383985007A0B6C /* Debug */, + 74556EDEC03158A3009CA84D67369133 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - ABCC3636B5EAEBE6D60D155704F40EBC /* Build configuration list for PBXNativeTarget "SwiftMessages" */ = { + 7D9EC6095BF15A96EABE2FE5045DA5DE /* Build configuration list for PBXNativeTarget "SwiftMessages" */ = { isa = XCConfigurationList; buildConfigurations = ( - F069CD2F5774D5082336F140E5F68B3A /* Debug */, - 7C5AE2DF0A930DD6AC66390486478632 /* Release */, + B9F08B726D3DD8C6ACDBB8CC2E05B693 /* Debug */, + D0E16784196812CD6F00BFEE04C50E82 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; From 1e49de7b3780b69927bc3e61903d8ec0693a3dc5 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Tue, 5 Oct 2021 13:11:30 -0500 Subject: [PATCH 109/139] Work/9.0.5 (#486) * Notifify will change before changes are made * Account for bounceAnimationOffset with keyboard avoidance * Release prep --- CHANGELOG.md | 7 +++++++ SwiftMessages.podspec | 2 +- SwiftMessages/KeyboardTrackingView.swift | 16 +++++++++++++++- SwiftMessages/MaskingView.swift | 11 ++++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed087150..de1f84a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.5 + +### Fixes + +* #482 Fix timing of `KeyboardTrackingView` callbacks. +* #483 KeyboardTrackingView causes a small space under bottom-style view + ## 9.0.4 * #471 Xcode 13 issue - Enum cases with associated values cannot be marked potentially unavailable with '@available' diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 688f100f..c43a5298 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.4' + spec.version = '9.0.5' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } diff --git a/SwiftMessages/KeyboardTrackingView.swift b/SwiftMessages/KeyboardTrackingView.swift index 6af384a6..301d969c 100644 --- a/SwiftMessages/KeyboardTrackingView.swift +++ b/SwiftMessages/KeyboardTrackingView.swift @@ -44,6 +44,18 @@ open class KeyboardTrackingView: UIView { /// The margin to maintain between the keyboard and the top of the view. @IBInspectable open var topMargin: CGFloat = 0 + /// Subclasses can override this to do something before the change. + open func willChange( + change: KeyboardTrackingView.Change, + userInfo: [AnyHashable : Any] + ) {} + + /// Subclasses can override this to do something after the change. + open func didChange( + change: KeyboardTrackingView.Change, + userInfo: [AnyHashable : Any] + ) {} + override public init(frame: CGRect) { super.init(frame: frame) postInit() @@ -101,11 +113,12 @@ open class KeyboardTrackingView: UIView { guard !(isPaused || isAutomaticallyPaused), let userInfo = (notification as NSNotification).userInfo, let value = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return } + willChange(change: change, userInfo: userInfo) + delegate?.keyboardTrackingViewWillChange(change: change, userInfo: userInfo) let keyboardRect = value.cgRectValue let thisRect = convert(bounds, to: nil) let newHeight = max(0, thisRect.maxY - keyboardRect.minY) + topMargin guard heightConstraint.constant != newHeight else { return } - delegate?.keyboardTrackingViewWillChange(change: change, userInfo: userInfo) animateKeyboardChange(change: change, height: newHeight, userInfo: userInfo) } @@ -115,6 +128,7 @@ open class KeyboardTrackingView: UIView { let curveNumber = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber { CATransaction.begin() CATransaction.setCompletionBlock { + self.didChange(change: change, userInfo: userInfo) self.delegate?.keyboardTrackingViewDidChange(change: change, userInfo: userInfo) } UIView.beginAnimations(nil, context: nil) diff --git a/SwiftMessages/MaskingView.swift b/SwiftMessages/MaskingView.swift index 0ce4c428..d6313427 100644 --- a/SwiftMessages/MaskingView.swift +++ b/SwiftMessages/MaskingView.swift @@ -65,6 +65,15 @@ class MaskingView: PassthroughView { guard let keyboardTrackingView = keyboardTrackingView, view != keyboardTrackingView, view != backgroundView else { return } - keyboardTrackingView.topAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor).with(priority: UILayoutPriority(250)).isActive = true + let offset: CGFloat + if let adjustable = view as? MarginAdjustable { + offset = -adjustable.bounceAnimationOffset + } else { + offset = 0 + } + keyboardTrackingView.topAnchor.constraint( + greaterThanOrEqualTo: view.bottomAnchor, + constant: offset + ).with(priority: UILayoutPriority(250)).isActive = true } } From b29dd21090b708aa0ae9ecbaf6e2d0487028dc3f Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Fri, 14 Jan 2022 11:33:00 -0600 Subject: [PATCH 110/139] Add view associated type to Event --- CHANGELOG.md | 7 +++++++ README.md | 4 +++- SwiftMessages.podspec | 2 +- SwiftMessages/Presenter.swift | 8 ++++---- SwiftMessages/SwiftMessages.swift | 21 +++++++++++++++++---- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de1f84a9..8c25038f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.6 + +### Features + +* Add `UIView` associated type to `Event`, e.g. `willShow(UIView)` so that event listeners can inspect the view. +* Add `Event.id: String?` property so that event listeners can reason about the view's ID. + ## 9.0.5 ### Fixes diff --git a/README.md b/README.md index c46c84cf..97e83746 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,9 @@ config.preferredStatusBarStyle = .lightContent // Specify one or more event listeners to respond to show and hide events. config.eventListeners.append() { event in - if case .didHide = event { print("yep") } + if case .didHide = event { + print("yep id=\(String(describing: event.id)") + } } SwiftMessages.show(config: config, view: view) diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index c43a5298..4c7b9451 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.5' + spec.version = '9.0.6' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index 11243f54..be093beb 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -119,7 +119,7 @@ class Presenter: NSObject { func show(completion: @escaping AnimationCompletion) throws { try presentationContext = getPresentationContext() install() - self.config.eventListeners.forEach { $0(.willShow) } + self.config.eventListeners.forEach { $0(.willShow(self.view)) } showAnimation() { completed in completion(completed) if completed { @@ -128,7 +128,7 @@ class Presenter: NSObject { } else { self.showAccessibilityAnnouncement() } - self.config.eventListeners.forEach { $0(.didShow) } + self.config.eventListeners.forEach { $0(.didShow(self.view)) } } } } @@ -181,7 +181,7 @@ class Presenter: NSObject { func hide(animated: Bool, completion: @escaping AnimationCompletion) { isHiding = true - self.config.eventListeners.forEach { $0(.willHide) } + self.config.eventListeners.forEach { $0(.willHide(self.view)) } let context = animationContext() let action = { if let viewController = self.presentationContext.viewControllerValue() as? WindowViewController { @@ -189,7 +189,7 @@ class Presenter: NSObject { } self.maskingView.removeFromSuperview() completion(true) - self.config.eventListeners.forEach { $0(.didHide) } + self.config.eventListeners.forEach { $0(.didHide(self.view)) } } guard animated else { action() diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index 7c0042f5..5e9f0c3c 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -219,10 +219,23 @@ open class SwiftMessages { Specifies events in the message lifecycle. */ public enum Event { - case willShow - case didShow - case willHide - case didHide + case willShow(UIView) + case didShow(UIView) + case willHide(UIView) + case didHide(UIView) + + public var view: UIView { + switch self { + case .willShow(let view): return view + case .didShow(let view): return view + case .willHide(let view): return view + case .didHide(let view): return view + } + } + + public var id: String? { + return (view as? Identifiable)?.id + } } /** From 4e49214f64f949cc00af225e1f6f4457f6fd62d5 Mon Sep 17 00:00:00 2001 From: mbastos Date: Sat, 14 May 2022 13:59:22 -0300 Subject: [PATCH 111/139] Add dynamically linked option in products (#495) --- Package.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 5324d1b7..a0f30e8b 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,8 @@ let package = Package( .iOS("9.0") ], products: [ - .library(name: "SwiftMessages", targets: ["SwiftMessages"]) + .library(name: "SwiftMessages", targets: ["SwiftMessages"]), + .library(name: "SwiftMessages-Dynamic", type: .dynamic, targets: ["SwiftMessages"]) ], targets: [ .target( From 3af7c4d5abf1a023c375b4f7d78f32cf12d02e5b Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 18 Sep 2023 11:56:20 -0500 Subject: [PATCH 112/139] Prevent orphaned views from blocking (#517) --- SwiftMessages/Presenter.swift | 10 +++++++++- SwiftMessages/SwiftMessages.swift | 8 ++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index be093beb..5a3648b8 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -68,6 +68,13 @@ class Presenter: NSObject { return duration } + /// Detects the scenario where the view was shown, but the containing view heirarchy was removed before the view + /// was hidden. This unusual scenario could result in the message queue being blocked because the presented + /// view was not properly hidden by SwiftMessages. `isOrphaned` allows the queuing logic to unblock the queue. + var isOrphaned: Bool { + return installed && view.window == nil + } + // MARK: - Constants enum PresentationContext { @@ -97,7 +104,7 @@ class Presenter: NSObject { private weak var delegate: PresenterDelegate? private var presentationContext = PresentationContext.viewController(Weak(value: nil)) - + private var installed = false private var interactivelyHidden = false; // MARK: - Showing and hiding @@ -412,6 +419,7 @@ class Presenter: NSObject { maskingView.accessibleElements = elements } + installed = true guard let containerView = presentationContext.viewValue() else { return } (presentationContext.viewControllerValue() as? WindowViewController)?.install() installMaskingView(containerView: containerView) diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index 5e9f0c3c..395bc0ad 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -586,7 +586,10 @@ open class SwiftMessages { fileprivate func enqueue(presenter: Presenter) { if presenter.config.ignoreDuplicates { counts[presenter.id] = (counts[presenter.id] ?? 0) + 1 - if _current?.id == presenter.id && _current?.isHiding == false { return } + if let _current, + _current.id == presenter.id, + !_current.isHiding, + !_current.isOrphaned { return } if queue.filter({ $0.id == presenter.id }).count > 0 { return } } func doEnqueue() { @@ -606,7 +609,8 @@ open class SwiftMessages { } fileprivate func dequeueNext() { - guard self._current == nil, queue.count > 0 else { return } + guard queue.count > 0 else { return } + if let _current, !_current.isOrphaned { return } let current = queue.removeFirst() self._current = current // Set `autohideToken` before the animation starts in case From 977436eeef05a0a21bee8e7f651cd12f5b7ef191 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 18 Sep 2023 12:12:49 -0500 Subject: [PATCH 113/139] Remove unowned reference --- SwiftMessages/SwiftMessagesSegue.swift | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index d4cba417..80c3939c 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -208,6 +208,7 @@ open class SwiftMessagesSegue: UIStoryboardSegue { override open func perform() { (source as? WindowViewController)?.install() selfRetainer = self + startReleaseMonitor() if overrideModalPresentationStyle { destination.modalPresentationStyle = .custom } @@ -222,6 +223,19 @@ open class SwiftMessagesSegue: UIStoryboardSegue { } fileprivate let safeAreaWorkaroundViewController = UIViewController() + + /// The self-retainer will not allow the segue, presenting and presented view controllers to be released if the presenting view controller + /// is removed without first dismissing. This monitor handles that scenario by setting `self.selfRetainer = nil` if + /// the presenting view controller is no longer in the heirarchy. + private func startReleaseMonitor() { + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in + guard let self = self else { return } + switch self.source.view.window { + case .none: self.selfRetainer = nil + case .some: self.startReleaseMonitor() + } + } + } } extension SwiftMessagesSegue { @@ -288,12 +302,13 @@ extension SwiftMessagesSegue { extension SwiftMessagesSegue: UIViewControllerTransitioningDelegate { public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { let shower = TransitioningPresenter(segue: self) - messenger.defaultConfig.eventListeners.append { [unowned self] in + let hider = self.hider + messenger.defaultConfig.eventListeners.append { [weak self] in switch $0 { case .didShow: shower.completeTransition?(true) case .didHide: - if let completeTransition = self.hider.completeTransition { + if let completeTransition = hider.completeTransition { completeTransition(true) } else { // Case where message is internally hidden by SwiftMessages, such as with a @@ -301,7 +316,7 @@ extension SwiftMessagesSegue: UIViewControllerTransitioningDelegate { source.dismiss(animated: false, completion: nil) } (source as? WindowViewController)?.uninstall() - self.selfRetainer = nil + self?.selfRetainer = nil default: break } } From 813938a829bc0599712c9001eb2298cc0ffe6fb6 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 18 Sep 2023 12:13:02 -0500 Subject: [PATCH 114/139] Update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c25038f..0a4ec930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.7 + +### Fixes + +* #527 Crash while clicking two times to hide the presenting controller +* #517 Prevent orphaned views from blocking the queue +* Prevent orphaned `SwiftMessagesSeque`s from retaining the presenting view controller + ## 9.0.6 ### Features From 6c16e58ce72f8e7549930e3d2c62e25e224e799b Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Fri, 6 Oct 2023 09:38:19 -0500 Subject: [PATCH 115/139] Add basic support for SwiftUI (#528) --- README.md | 103 ++++- SwiftMessages.podspec | 6 +- SwiftMessages.xcodeproj/project.pbxproj | 72 ++- .../xcschemes/SwiftMessages.xcscheme | 2 +- SwiftMessages/BaseView.swift | 4 +- SwiftMessages/Identifiable.swift | 1 + SwiftMessages/MessageHostingView.swift | 42 ++ SwiftMessages/MessageViewConvertible.swift | 16 + SwiftMessages/SwiftMessageModifier.swift | 62 +++ SwiftMessages/SwiftMessagesSegue.swift | 8 - .../SwiftUIDemo.xcodeproj/project.pbxproj | 436 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../SwiftUIDemo/Assets.xcassets/Contents.json | 6 + .../Contents.json | 20 + SwiftUIDemo/SwiftUIDemo/DemoMessage.swift | 22 + SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift | 35 ++ SwiftUIDemo/SwiftUIDemo/DemoView.swift | 48 ++ SwiftUIDemo/SwiftUIDemo/Info.plist | 5 + .../Preview Assets.xcassets/Contents.json | 6 + SwiftUIDemo/SwiftUIDemo/SwiftUIDemoApp.swift | 17 + 23 files changed, 910 insertions(+), 40 deletions(-) create mode 100644 SwiftMessages/MessageHostingView.swift create mode 100644 SwiftMessages/MessageViewConvertible.swift create mode 100644 SwiftMessages/SwiftMessageModifier.swift create mode 100644 SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj create mode 100644 SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Contents.json create mode 100644 SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Demo message background.colorset/Contents.json create mode 100644 SwiftUIDemo/SwiftUIDemo/DemoMessage.swift create mode 100644 SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift create mode 100644 SwiftUIDemo/SwiftUIDemo/DemoView.swift create mode 100644 SwiftUIDemo/SwiftUIDemo/Info.plist create mode 100644 SwiftUIDemo/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 SwiftUIDemo/SwiftUIDemo/SwiftUIDemoApp.swift diff --git a/README.md b/README.md index 97e83746..0cf8e79d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ SwiftMessages is a very flexible view and view controller presentation library f Message views and view controllers can be displayed at the top, bottom, or center of the screen, or behind navigation bars and tab bars. There are interactive dismiss gestures including a fun, physics-based one. Multiple background dimming modes. And a lot more! +πŸ”₯ Now supports displaying SwiftUI message views πŸ”₯ + In addition to the numerous configuration options, SwiftMessages provides several good-looking layouts and themes. But SwiftMessages is also designer-friendly, which means you can fully and easily customize the view: * Copy one of the included nib files into your project and change it. @@ -32,19 +34,6 @@ Try exploring [the demo app via appetize.io](http://goo.gl/KXw4nD) to get a feel

-## View Controllers - -SwiftMessages can present view controllers using the `SwiftMessagesSegue` custom modal segue! - -

- -

- -[`SwiftMessagesSegue`](./SwiftMessages/SwiftMessagesSegue.swift) is a subclass of `UIStoryboardSegue` that integrates directly into Interface Builder as a custom modal segue, enabling view controllers to take advantage of SwiftMessages layouts, animations and more. `SwiftMessagesSegue` works with any UIKIt project β€” storyboards are not required. Refer to the View Controllers readme below for more information. - -#### [View Controllers Readme](./ViewControllers.md) - -And check out our blog post [Elegant Custom UIViewController Transitioning](http://www.swiftkickmobile.com/elegant-custom-uiviewcontroller-transitioning-uiviewcontrollertransitioningdelegate-uiviewcontrolleranimatedtransitioning/) to learn a great technique you can use to build your own custom segues that utilize `UIViewControllerTransitioningDelegate` and `UIViewControllerAnimatedTransitioning`. ## Installation @@ -178,6 +167,94 @@ config.duration = .forever SwiftMessages.show(config: config, view: view) ```` +### View Controllers + +SwiftMessages can present view controllers using the `SwiftMessagesSegue` custom modal segue! + +

+ +

+ +[`SwiftMessagesSegue`](./SwiftMessages/SwiftMessagesSegue.swift) is a subclass of `UIStoryboardSegue` that integrates directly into Interface Builder as a custom modal segue, enabling view controllers to take advantage of SwiftMessages layouts, animations and more. `SwiftMessagesSegue` works with any UIKIt project β€” storyboards are not required. Refer to the View Controllers readme below for more information. + +#### [View Controllers Readme](./ViewControllers.md) + +And check out our blog post [Elegant Custom UIViewController Transitioning](http://www.swiftkickmobile.com/elegant-custom-uiviewcontroller-transitioning-uiviewcontrollertransitioningdelegate-uiviewcontrolleranimatedtransitioning/) to learn a great technique you can use to build your own custom segues that utilize `UIViewControllerTransitioningDelegate` and `UIViewControllerAnimatedTransitioning`. + +### SwiftUI + +Any of the built-in SwiftMessages views can be displayed by calling the SwiftMessages APIs from within observable object, a button action closure, etc. However, SwiftMessages can also display your custom SwiftUI views. + +First, define a type that conforms to `MessageViewConvertible`. This will typically be a struct containing the message data: + + +````swift +struct DemoMessage: Identifiable { + let title: String + let body: String + + var id: String { title + body } +} + +extension DemoMessage: MessageViewConvertible { + func asMessageView() -> DemoMessageView { + DemoMessageView(message: self) + } +} + +struct DemoMessageView: View { + + let message: DemoMessage + + var body: some View { + VStack(alignment: .leading) { + Text(message.title).font(.system(size: 20, weight: .bold)) + Text(message.body) + } + .multilineTextAlignment(.leading) + .padding(30) + .frame(maxWidth: .infinity) + .background(.gray) + .cornerRadius(15) + .padding(15) + } +} +```` + +The SwiftUI message view can be displayed just like any other UIKit message by using `MessageHostingView`: + +````swift +struct DemoView: View { + var body: some View { + Button("Show message") { + let message = DemoMessage(title: "Demo", body: "SwiftUI forever!") + let messageView = MessageHostingView(message: message) + SwiftMessages.show(view: messageView) + } + } +} +```` + +But you may also use a state-based approach using the `swiftMessage()` view modifier: + +````swift +struct DemoView: View { + + @State var message: DemoMessage? + + var body: some View { + Button("Show message") { + message = DemoMessage(title: "Demo", body: "SwiftUI forever!") + } + .swiftMessage(message: $message) + } +} +```` + +This technique may be more SwiftUI-like, but it doesn't offer the full capability of SwiftMessages, such as explicitly hiding messages by their ID. It is totally reasonable to use a combination of both approaches. + +Try it out in the SwiftUI demo app! + ### Accessibility SwiftMessages provides excellent VoiceOver support out-of-the-box. diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 4c7b9451..00b6a817 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.6' + spec.version = '9.0.7' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } spec.summary = 'A very flexible message bar for iOS written in Swift.' spec.source = {:git => 'https://github.com/SwiftKickMobile/SwiftMessages.git', :tag => spec.version} - spec.platform = :ios, '9.0' + spec.platform = :ios, '12.0' spec.swift_version = '5.0' - spec.ios.deployment_target = '9.0' + spec.ios.deployment_target = '12.0' spec.framework = 'UIKit' spec.requires_arc = true spec.default_subspec = 'App' diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index b01d9c2f..45809f2d 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -52,6 +52,9 @@ 228DF5681FAD0806004F8A39 /* infoIconSubtle.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */; }; 228DF5691FAD0806004F8A39 /* successIconLight.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5481FAD0805004F8A39 /* successIconLight.png */; }; 228DF56A1FAD0806004F8A39 /* infoIconSubtle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */; }; + 228F7DDE2ACF703A006C9644 /* MessageHostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DDB2ACF7039006C9644 /* MessageHostingView.swift */; }; + 228F7DDF2ACF703A006C9644 /* SwiftMessageModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DDC2ACF703A006C9644 /* SwiftMessageModifier.swift */; }; + 228F7DE02ACF703A006C9644 /* MessageViewConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DDD2ACF703A006C9644 /* MessageViewConvertible.swift */; }; 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2041EE47DC900E2DDC1 /* Weak.swift */; }; 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; @@ -140,6 +143,9 @@ 228DF5471FAD0805004F8A39 /* infoIconSubtle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = infoIconSubtle.png; path = Resources/infoIconSubtle.png; sourceTree = ""; }; 228DF5481FAD0805004F8A39 /* successIconLight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = successIconLight.png; path = Resources/successIconLight.png; sourceTree = ""; }; 228DF5491FAD0805004F8A39 /* infoIconSubtle@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "infoIconSubtle@3x.png"; path = "Resources/infoIconSubtle@3x.png"; sourceTree = ""; }; + 228F7DDB2ACF7039006C9644 /* MessageHostingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHostingView.swift; sourceTree = ""; }; + 228F7DDC2ACF703A006C9644 /* SwiftMessageModifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftMessageModifier.swift; sourceTree = ""; }; + 228F7DDD2ACF703A006C9644 /* MessageViewConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageViewConvertible.swift; sourceTree = ""; }; 2298C2041EE47DC900E2DDC1 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = ""; }; 2298C2061EE480D000E2DDC1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; }; 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; @@ -235,6 +241,15 @@ name = Frameworks; sourceTree = ""; }; + 228F7DDA2ACF7029006C9644 /* SwiftUI */ = { + isa = PBXGroup; + children = ( + 228F7DDC2ACF703A006C9644 /* SwiftMessageModifier.swift */, + 228F7DDD2ACF703A006C9644 /* MessageViewConvertible.swift */, + ); + name = SwiftUI; + sourceTree = ""; + }; 22D4779B20BF1C54005D0D71 /* View Controllers */ = { isa = PBXGroup; children = ( @@ -339,6 +354,7 @@ 86AAF8171D54F0650031EE32 /* PassthroughView.swift */, 22E01F631E74EC8B00ACE19A /* MaskingView.swift */, 86AAF8191D54F0850031EE32 /* PassthroughWindow.swift */, + 228F7DDB2ACF7039006C9644 /* MessageHostingView.swift */, 220D38672597A94C00BB2B88 /* Extensions */, ); name = Internal; @@ -352,6 +368,7 @@ 862C0CD81D5A396900D06168 /* Resources */, 2244656C1EF1D62700C50413 /* Animations */, 22D4779B20BF1C54005D0D71 /* View Controllers */, + 228F7DDA2ACF7029006C9644 /* SwiftUI */, 864495571D4F7C490056EB2A /* Base */, 220D38682597A9FD00BB2B88 /* Extensions */, 867E218E1D4D3DFD00594A41 /* Internal */, @@ -434,8 +451,9 @@ 867E21471D4D01D500594A41 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 1200; + LastUpgradeCheck = 1500; ORGANIZATIONNAME = "SwiftKick Mobile"; TargetAttributes = { 86B48AEB1D5A41C900063E2B = { @@ -539,13 +557,16 @@ 86BBA9011D5E040600FE8F16 /* PassthroughWindow.swift in Sources */, 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */, 86BBA9031D5E040600FE8F16 /* UIViewController+Extensions.swift in Sources */, + 228F7DDF2ACF703A006C9644 /* SwiftMessageModifier.swift in Sources */, 224FB69921153B440081D4DE /* CALayer+Extensions.swift in Sources */, 22E01F641E74EC8B00ACE19A /* MaskingView.swift in Sources */, 2298C2051EE47DC900E2DDC1 /* Weak.swift in Sources */, + 228F7DE02ACF703A006C9644 /* MessageViewConvertible.swift in Sources */, 86BBA9001D5E040600FE8F16 /* PassthroughView.swift in Sources */, 22DFC9181F00674E001B1CA1 /* PhysicsPanHandler.swift in Sources */, 227BA6D920BF224A00E5A843 /* SwiftMessagesSegue.swift in Sources */, 220655121FAF82B600F4E00F /* MarginAdjustable+Extensions.swift in Sources */, + 228F7DDE2ACF703A006C9644 /* MessageHostingView.swift in Sources */, 22E307FF1E74C5B100E35893 /* AccessibleMessage.swift in Sources */, 220D386E2597AA5B00BB2B88 /* SwiftMessages.Config+Extensions.swift in Sources */, 2270044B1FAFA6DD0045DDC3 /* PhysicsAnimation.swift in Sources */, @@ -619,6 +640,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -633,7 +655,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.1; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -677,6 +699,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -685,10 +708,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.1; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 3.0; VALIDATE_PRODUCT = YES; }; @@ -698,17 +722,24 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_IDENTITY = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessages; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -726,17 +757,24 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CODE_SIGN_IDENTITY = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessages; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -753,7 +791,11 @@ isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = SwiftMessagesTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessagesTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; @@ -765,7 +807,11 @@ isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = SwiftMessagesTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = it.swiftkick.SwiftMessagesTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; diff --git a/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme b/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme index ad3b2531..5c84455f 100644 --- a/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme +++ b/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme @@ -1,6 +1,6 @@ : BaseView, Identifiable where Content: View { + + // MARK: - API + + public let id: String + + public init(message: Message) where Message: MessageViewConvertible, Message.Content == Content { + let messageView: Content = message.asMessageView() + hostVC = UIHostingController(rootView: messageView) + id = message.id + super.init(frame: .zero) + hostVC.loadViewIfNeeded() + installContentView(hostVC.view) + backgroundColor = .clear + hostVC.view.backgroundColor = .clear + } + + // MARK: - Constants + + // MARK: - Variables + + private let hostVC: UIHostingController + + // MARK: - Lifecycle + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/SwiftMessages/MessageViewConvertible.swift b/SwiftMessages/MessageViewConvertible.swift new file mode 100644 index 00000000..6dc168bf --- /dev/null +++ b/SwiftMessages/MessageViewConvertible.swift @@ -0,0 +1,16 @@ +// +// MessageViewConvertible.swift +// SwiftUIDemo +// +// Created by Timothy Moose on 10/5/23. +// + +import SwiftUI + +@available(iOS 14.0, *) +/// A protocol used to display a SwiftUI message view using the `swiftMessage()` modifier. +public protocol MessageViewConvertible: Equatable, Identifiable { + associatedtype Content: View + func asMessageView() -> Content +} + diff --git a/SwiftMessages/SwiftMessageModifier.swift b/SwiftMessages/SwiftMessageModifier.swift new file mode 100644 index 00000000..479b6d91 --- /dev/null +++ b/SwiftMessages/SwiftMessageModifier.swift @@ -0,0 +1,62 @@ +// +// SwiftMessageModifier.swift +// SwiftUIDemo +// +// Created by Timothy Moose on 10/5/23. +// + +import SwiftUI + +@available(iOS 14.0, *) +public extension View { + /// A state-based modifier for displaying a message. + func swiftMessage( + message: Binding, + config: SwiftMessages.Config? = nil, + swiftMessages: SwiftMessages? = nil + ) -> some View where Message: MessageViewConvertible { + modifier(SwiftMessageModifier(message: message, config: config, swiftMessages: swiftMessages)) + } +} + +@available(iOS 14.0, *) +private struct SwiftMessageModifier: ViewModifier where Message: MessageViewConvertible { + // MARK: - API + + fileprivate init( + message: Binding, + config: SwiftMessages.Config? = nil, + swiftMessages: SwiftMessages? = nil + ) { + _message = message + self.config = config + self.swiftMessages = swiftMessages + } + + // MARK: - Constants + + // MARK: - Variables + + @Binding private var message: Message? + private let config: SwiftMessages.Config? + private let swiftMessages: SwiftMessages? + + // MARK: - Body + + func body(content: Content) -> some View { + content + .onChange(of: message) { _ in + if let message { + let show: (SwiftMessages.Config, UIView) -> Void = swiftMessages?.show(config:view:) ?? SwiftMessages.show(config:view:) + let view = MessageHostingView(message: message) + var config = config ?? swiftMessages?.defaultConfig ?? SwiftMessages.defaultConfig + config.eventListeners.append { event in + if case .didHide = event, event.id == self.message?.id { + self.message = nil + } + } + show(config, view) + } + } + } +} diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index 80c3939c..cd17eec3 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -348,14 +348,6 @@ extension SwiftMessagesSegue { transitionContext.completeTransition(false) return } - if #available(iOS 12, *) {} - else if #available(iOS 11.0, *) { - // This works around a bug in iOS 11 where the safe area of `messageView` ( - // and all ancestor views) is not set except on iPhone X. By assigning `messageView` - // to a view controller, its safe area is set consistently. This bug has been resolved as - // of Xcode 10 beta 2. - segue.safeAreaWorkaroundViewController.view = segue.presenter.maskingView - } completeTransition = transitionContext.completeTransition let transitionContainer = transitionContext.containerView toView.translatesAutoresizingMaskIntoConstraints = false diff --git a/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj new file mode 100644 index 00000000..8b289e23 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj @@ -0,0 +1,436 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 228F7DAD2ACF17E8006C9644 /* SwiftUIDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DAC2ACF17E8006C9644 /* SwiftUIDemoApp.swift */; }; + 228F7DAF2ACF17E8006C9644 /* DemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DAE2ACF17E8006C9644 /* DemoView.swift */; }; + 228F7DB12ACF17E9006C9644 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 228F7DB02ACF17E9006C9644 /* Assets.xcassets */; }; + 228F7DB42ACF17E9006C9644 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 228F7DB32ACF17E9006C9644 /* Preview Assets.xcassets */; }; + 228F7DC82ACF1E63006C9644 /* SwiftMessages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 228F7DC32ACF1E1E006C9644 /* SwiftMessages.framework */; }; + 228F7DC92ACF1E63006C9644 /* SwiftMessages.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 228F7DC32ACF1E1E006C9644 /* SwiftMessages.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 228F7DD52ACF59E4006C9644 /* DemoMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DD42ACF59E4006C9644 /* DemoMessage.swift */; }; + 228F7DD72ACF5C2E006C9644 /* DemoMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DD62ACF5C2E006C9644 /* DemoMessageView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 228F7DC22ACF1E1E006C9644 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 228F7DBD2ACF1E1E006C9644 /* SwiftMessages.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 86B48AEC1D5A41C900063E2B; + remoteInfo = SwiftMessages; + }; + 228F7DC42ACF1E1E006C9644 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 228F7DBD2ACF1E1E006C9644 /* SwiftMessages.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 86B48AF51D5A41C900063E2B; + remoteInfo = SwiftMessagesTests; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 228F7DCA2ACF1E63006C9644 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 228F7DC92ACF1E63006C9644 /* SwiftMessages.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 228F7DA92ACF17E8006C9644 /* SwiftUIDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 228F7DAC2ACF17E8006C9644 /* SwiftUIDemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIDemoApp.swift; sourceTree = ""; }; + 228F7DAE2ACF17E8006C9644 /* DemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoView.swift; sourceTree = ""; }; + 228F7DB02ACF17E9006C9644 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 228F7DB32ACF17E9006C9644 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 228F7DBB2ACF1DB5006C9644 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 228F7DBD2ACF1E1E006C9644 /* SwiftMessages.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftMessages.xcodeproj; path = ../SwiftMessages.xcodeproj; sourceTree = ""; }; + 228F7DD42ACF59E4006C9644 /* DemoMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoMessage.swift; sourceTree = ""; }; + 228F7DD62ACF5C2E006C9644 /* DemoMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoMessageView.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 228F7DA62ACF17E8006C9644 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 228F7DC82ACF1E63006C9644 /* SwiftMessages.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 228F7DA02ACF17E8006C9644 = { + isa = PBXGroup; + children = ( + 228F7DAB2ACF17E8006C9644 /* SwiftUIDemo */, + 228F7DAA2ACF17E8006C9644 /* Products */, + 228F7DC72ACF1E63006C9644 /* Frameworks */, + 228F7DBD2ACF1E1E006C9644 /* SwiftMessages.xcodeproj */, + ); + sourceTree = ""; + }; + 228F7DAA2ACF17E8006C9644 /* Products */ = { + isa = PBXGroup; + children = ( + 228F7DA92ACF17E8006C9644 /* SwiftUIDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + 228F7DAB2ACF17E8006C9644 /* SwiftUIDemo */ = { + isa = PBXGroup; + children = ( + 228F7DBB2ACF1DB5006C9644 /* Info.plist */, + 228F7DAC2ACF17E8006C9644 /* SwiftUIDemoApp.swift */, + 228F7DAE2ACF17E8006C9644 /* DemoView.swift */, + 228F7DD42ACF59E4006C9644 /* DemoMessage.swift */, + 228F7DD62ACF5C2E006C9644 /* DemoMessageView.swift */, + 228F7DB02ACF17E9006C9644 /* Assets.xcassets */, + 228F7DB22ACF17E9006C9644 /* Preview Content */, + ); + path = SwiftUIDemo; + sourceTree = ""; + }; + 228F7DB22ACF17E9006C9644 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 228F7DB32ACF17E9006C9644 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 228F7DBE2ACF1E1E006C9644 /* Products */ = { + isa = PBXGroup; + children = ( + 228F7DC32ACF1E1E006C9644 /* SwiftMessages.framework */, + 228F7DC52ACF1E1E006C9644 /* SwiftMessagesTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 228F7DC72ACF1E63006C9644 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 228F7DA82ACF17E8006C9644 /* SwiftUIDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 228F7DB72ACF17E9006C9644 /* Build configuration list for PBXNativeTarget "SwiftUIDemo" */; + buildPhases = ( + 228F7DA52ACF17E8006C9644 /* Sources */, + 228F7DA62ACF17E8006C9644 /* Frameworks */, + 228F7DA72ACF17E8006C9644 /* Resources */, + 228F7DCA2ACF1E63006C9644 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftUIDemo; + productName = SwiftUIDemo; + productReference = 228F7DA92ACF17E8006C9644 /* SwiftUIDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 228F7DA12ACF17E8006C9644 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1500; + TargetAttributes = { + 228F7DA82ACF17E8006C9644 = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = 228F7DA42ACF17E8006C9644 /* Build configuration list for PBXProject "SwiftUIDemo" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 228F7DA02ACF17E8006C9644; + productRefGroup = 228F7DAA2ACF17E8006C9644 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 228F7DBE2ACF1E1E006C9644 /* Products */; + ProjectRef = 228F7DBD2ACF1E1E006C9644 /* SwiftMessages.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 228F7DA82ACF17E8006C9644 /* SwiftUIDemo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 228F7DC32ACF1E1E006C9644 /* SwiftMessages.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = SwiftMessages.framework; + remoteRef = 228F7DC22ACF1E1E006C9644 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 228F7DC52ACF1E1E006C9644 /* SwiftMessagesTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = SwiftMessagesTests.xctest; + remoteRef = 228F7DC42ACF1E1E006C9644 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 228F7DA72ACF17E8006C9644 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 228F7DB42ACF17E9006C9644 /* Preview Assets.xcassets in Resources */, + 228F7DB12ACF17E9006C9644 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 228F7DA52ACF17E8006C9644 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 228F7DD52ACF59E4006C9644 /* DemoMessage.swift in Sources */, + 228F7DD72ACF5C2E006C9644 /* DemoMessageView.swift in Sources */, + 228F7DAF2ACF17E8006C9644 /* DemoView.swift in Sources */, + 228F7DAD2ACF17E8006C9644 /* SwiftUIDemoApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 228F7DB52ACF17E9006C9644 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + 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; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + 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 = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 228F7DB62ACF17E9006C9644 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + 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; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + 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 = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 228F7DB82ACF17E9006C9644 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"SwiftUIDemo/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SwiftUIDemo/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.swiftkickmobile.SwiftUIDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 228F7DB92ACF17E9006C9644 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"SwiftUIDemo/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SwiftUIDemo/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.swiftkickmobile.SwiftUIDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 228F7DA42ACF17E8006C9644 /* Build configuration list for PBXProject "SwiftUIDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 228F7DB52ACF17E9006C9644 /* Debug */, + 228F7DB62ACF17E9006C9644 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 228F7DB72ACF17E9006C9644 /* Build configuration list for PBXNativeTarget "SwiftUIDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 228F7DB82ACF17E9006C9644 /* Debug */, + 228F7DB92ACF17E9006C9644 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 228F7DA12ACF17E8006C9644 /* Project object */; +} diff --git a/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..13613e3e --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Contents.json b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Demo message background.colorset/Contents.json b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Demo message background.colorset/Contents.json new file mode 100644 index 00000000..15b79d47 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/Assets.xcassets/Demo message background.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xEB", + "green" : "0xE1", + "red" : "0xAC" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SwiftUIDemo/SwiftUIDemo/DemoMessage.swift b/SwiftUIDemo/SwiftUIDemo/DemoMessage.swift new file mode 100644 index 00000000..ccc86b66 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/DemoMessage.swift @@ -0,0 +1,22 @@ +// +// DemoMessage.swift +// SwiftUIDemo +// +// Created by Timothy Moose on 10/5/23. +// + +import SwiftUI +import SwiftMessages + +struct DemoMessage: Identifiable { + let title: String + let body: String + + var id: String { title + body } +} + +extension DemoMessage: MessageViewConvertible { + func asMessageView() -> DemoMessageView { + DemoMessageView(message: self) + } +} diff --git a/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift new file mode 100644 index 00000000..cce5058c --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift @@ -0,0 +1,35 @@ +// +// DemoMessageView.swift +// SwiftUIDemo +// +// Created by Timothy Moose on 10/5/23. +// + +import SwiftUI + +struct DemoMessageView: View { + + // MARK: - API + + let message: DemoMessage + + // MARK: - Variables + + // MARK: - Constants + + // MARK: - Body + + var body: some View { + VStack(alignment: .leading) { + Text(message.title).font(.system(size: 20, weight: .bold)) + Text(message.body) + } + .multilineTextAlignment(.leading) + .padding(30) + .frame(maxWidth: .infinity) + .background(.demoMessageBackground) + .cornerRadius(15) + .padding(15) + } +} + diff --git a/SwiftUIDemo/SwiftUIDemo/DemoView.swift b/SwiftUIDemo/SwiftUIDemo/DemoView.swift new file mode 100644 index 00000000..e0bcd6c1 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/DemoView.swift @@ -0,0 +1,48 @@ +// +// DemoView.swift +// SwiftUIDemo +// +// Created by Timothy Moose on 10/5/23. +// + +import SwiftUI +import SwiftMessages + +struct DemoView: View { + + @State var message: DemoMessage? + + var body: some View { + Button("Show message") { + message = DemoMessage(title: "Demo", body: "This is a sample SwiftUI message! This content should be long enough to wrap.") + } + .buttonBorderShape(.roundedRectangle(radius: 15)) + .swiftMessage(message: $message) + } +} + +#Preview { + DemoView() +} + +struct DemoViewx: View { + var body: some View { + Button("Show message") { + let message = DemoMessage(title: "Demo", body: "SwiftUI forever!") + let messageView = MessageHostingView(message: message) + SwiftMessages.show(view: messageView) + } + } +} + +struct DemoViewy: View { + + @State var message: DemoMessage? + + var body: some View { + Button("Show message") { + message = DemoMessage(title: "Demo", body: "SwiftUI forever!") + } + .swiftMessage(message: $message) + } +} diff --git a/SwiftUIDemo/SwiftUIDemo/Info.plist b/SwiftUIDemo/SwiftUIDemo/Info.plist new file mode 100644 index 00000000..0c67376e --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/Info.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/SwiftUIDemo/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json b/SwiftUIDemo/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SwiftUIDemo/SwiftUIDemo/SwiftUIDemoApp.swift b/SwiftUIDemo/SwiftUIDemo/SwiftUIDemoApp.swift new file mode 100644 index 00000000..fc444543 --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/SwiftUIDemoApp.swift @@ -0,0 +1,17 @@ +// +// SwiftUIDemoApp.swift +// SwiftUIDemo +// +// Created by Timothy Moose on 10/5/23. +// + +import SwiftUI + +@main +struct SwiftUIDemoApp: App { + var body: some Scene { + WindowGroup { + DemoView() + } + } +} From 947c4e065409de7cae61e5f70a37f366a65f3ec6 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Fri, 6 Oct 2023 09:46:04 -0500 Subject: [PATCH 116/139] Update SwiftUI comments in README.md --- README.md | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0cf8e79d..8cb208bb 100644 --- a/README.md +++ b/README.md @@ -12,29 +12,22 @@ ## Overview -SwiftMessages is a very flexible view and view controller presentation library for iOS. +πŸ”₯πŸ”₯πŸ”₯ **NEW** SwiftUI support added! -Message views and view controllers can be displayed at the top, bottom, or center of the screen, or behind navigation bars and tab bars. There are interactive dismiss gestures including a fun, physics-based one. Multiple background dimming modes. And a lot more! +SwiftMessages is a very flexible view and view controller presentation library for UIKit and SwiftUI. -πŸ”₯ Now supports displaying SwiftUI message views πŸ”₯ +Message views and view controllers can be displayed at the top, bottom, or center of the screen, or behind navigation bars and tab bars. There are interactive dismiss gestures including a fun, physics-based one. Multiple background dimming modes. And a lot more! In addition to the numerous configuration options, SwiftMessages provides several good-looking layouts and themes. But SwiftMessages is also designer-friendly, which means you can fully and easily customize the view: * Copy one of the included nib files into your project and change it. * Subclass `MessageView` and add elements, etc. -* Or just supply an arbitrary instance of `UIView`. - -Try exploring [the demo app via appetize.io](http://goo.gl/KXw4nD) to get a feel for the extensive configurability of SwiftMessages. +* Or just supply an arbitrary instance of `View` or `UIView`.

-

- -

- - ## Installation ### Swift Package Manager @@ -185,7 +178,7 @@ And check out our blog post [Elegant Custom UIViewController Transitioning](http Any of the built-in SwiftMessages views can be displayed by calling the SwiftMessages APIs from within observable object, a button action closure, etc. However, SwiftMessages can also display your custom SwiftUI views. -First, define a type that conforms to `MessageViewConvertible`. This will typically be a struct containing the message data: +The first step is to define a type that conforms to `MessageViewConvertible`. This would typically be a struct containing the message data to display: ````swift From 691e9bf4656e5e7b47a66220770b5101b502574d Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Fri, 6 Oct 2023 09:47:53 -0500 Subject: [PATCH 117/139] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a4ec930..fdb8977e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. ## 9.0.7 +### Features + +* Added support for SwiftUI + ### Fixes * #527 Crash while clicking two times to hide the presenting controller From 188705b897cbc38e3f1e993978b5b7e46906e958 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Fri, 6 Oct 2023 09:55:16 -0500 Subject: [PATCH 118/139] Fix email address --- SwiftMessages.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 00b6a817..941a9827 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |spec| spec.version = '9.0.7' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' - spec.authors = { 'Timothy Moose' => 'tim@swiftkick.it' } + spec.authors = { 'Timothy Moose' => 'tim@swiftkickmobile.com' } spec.summary = 'A very flexible message bar for iOS written in Swift.' spec.source = {:git => 'https://github.com/SwiftKickMobile/SwiftMessages.git', :tag => spec.version} spec.platform = :ios, '12.0' From c2bcb351434ae044a486803ad1751b0e10f0d4e1 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sat, 7 Oct 2023 14:13:34 -0500 Subject: [PATCH 119/139] Address #529 --- CHANGELOG.md | 6 +++++ README.md | 10 +++++++-- SwiftMessages.podspec | 2 +- .../SwiftUIDemo.xcodeproj/project.pbxproj | 4 ++++ SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift | 11 +++++++--- SwiftUIDemo/SwiftUIDemo/DemoView.swift | 22 ------------------- 6 files changed, 27 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb8977e..d17b7a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.8 + +### Changes + +* #529 Update readme and SwiftUI demo to demostrate how to mask edges. + ## 9.0.7 ### Features diff --git a/README.md b/README.md index 8cb208bb..10ec0f22 100644 --- a/README.md +++ b/README.md @@ -208,8 +208,14 @@ struct DemoMessageView: View { .padding(30) .frame(maxWidth: .infinity) .background(.gray) - .cornerRadius(15) - .padding(15) + // This makes a tab-style view where the bottom corners are rounded and the view's background + // extends to the top edge. + .mask( + UnevenRoundedRectangle( + cornerRadii: .init(bottomLeading: 15, bottomTrailing: 15) + ) + .edgesIgnoringSafeArea(.top) + ) } } ```` diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 941a9827..e67d4b08 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.7' + spec.version = '9.0.8' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkickmobile.com' } diff --git a/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj index 8b289e23..f6c945bc 100644 --- a/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj +++ b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj @@ -58,6 +58,8 @@ 228F7DBD2ACF1E1E006C9644 /* SwiftMessages.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftMessages.xcodeproj; path = ../SwiftMessages.xcodeproj; sourceTree = ""; }; 228F7DD42ACF59E4006C9644 /* DemoMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoMessage.swift; sourceTree = ""; }; 228F7DD62ACF5C2E006C9644 /* DemoMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoMessageView.swift; sourceTree = ""; }; + 2291AA492AD1E3EC0084868E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; + 2291AA4C2AD1E4520084868E /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -75,6 +77,8 @@ 228F7DA02ACF17E8006C9644 = { isa = PBXGroup; children = ( + 2291AA4C2AD1E4520084868E /* CHANGELOG.md */, + 2291AA492AD1E3EC0084868E /* README.md */, 228F7DAB2ACF17E8006C9644 /* SwiftUIDemo */, 228F7DAA2ACF17E8006C9644 /* Products */, 228F7DC72ACF1E63006C9644 /* Frameworks */, diff --git a/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift index cce5058c..a299c356 100644 --- a/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift +++ b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift @@ -28,8 +28,13 @@ struct DemoMessageView: View { .padding(30) .frame(maxWidth: .infinity) .background(.demoMessageBackground) - .cornerRadius(15) - .padding(15) + // This makes a tab-style view where the bottom corners are rounded and the view's background + // extends to the top edge. + .mask( + UnevenRoundedRectangle( + cornerRadii: .init(bottomLeading: 15, bottomTrailing: 15) + ) + .edgesIgnoringSafeArea(.top) + ) } } - diff --git a/SwiftUIDemo/SwiftUIDemo/DemoView.swift b/SwiftUIDemo/SwiftUIDemo/DemoView.swift index e0bcd6c1..a6736d89 100644 --- a/SwiftUIDemo/SwiftUIDemo/DemoView.swift +++ b/SwiftUIDemo/SwiftUIDemo/DemoView.swift @@ -24,25 +24,3 @@ struct DemoView: View { #Preview { DemoView() } - -struct DemoViewx: View { - var body: some View { - Button("Show message") { - let message = DemoMessage(title: "Demo", body: "SwiftUI forever!") - let messageView = MessageHostingView(message: message) - SwiftMessages.show(view: messageView) - } - } -} - -struct DemoViewy: View { - - @State var message: DemoMessage? - - var body: some View { - Button("Show message") { - message = DemoMessage(title: "Demo", body: "SwiftUI forever!") - } - .swiftMessage(message: $message) - } -} From 62e12e138fc3eedf88c7553dd5d98712aa119f40 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Wed, 1 Nov 2023 12:59:03 -0500 Subject: [PATCH 120/139] Couple of fixes --- CHANGELOG.md | 7 +++ README.md | 10 ++-- SwiftMessages.podspec | 2 +- SwiftMessages/KeyboardTrackingView.swift | 17 +++++-- SwiftMessages/MessageHostingView.swift | 8 ++++ SwiftUIDemo/SwiftUIDemo/DemoMessage.swift | 3 +- SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift | 46 +++++++++++++++---- SwiftUIDemo/SwiftUIDemo/DemoView.swift | 26 +++++++++-- 8 files changed, 98 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d17b7a82..0f5cc826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.9 + +### Fixes + +* Fix hit testing on SwiftUI views to allow touches around the view's margins to pass through to the underlying view. +* Update `KeyboardTrackingView` to continue tracking the keyboard even when not installed in the view hierarchy. + ## 9.0.8 ### Changes diff --git a/README.md b/README.md index 10ec0f22..5af94cb4 100644 --- a/README.md +++ b/README.md @@ -206,14 +206,14 @@ struct DemoMessageView: View { } .multilineTextAlignment(.leading) .padding(30) + // This makes the message width greedy .frame(maxWidth: .infinity) .background(.gray) - // This makes a tab-style view where the bottom corners are rounded and the view's background - // extends to the top edge. + // This makes a tab-style view where the bottom corners are rounded and + // the view's background extends to the top edge. .mask( - UnevenRoundedRectangle( - cornerRadii: .init(bottomLeading: 15, bottomTrailing: 15) - ) + UnevenRoundedRectangle(bottomLeadingRadius: 15, bottomTrailingRadius: 15) + // This causes the background to extend into the safe area to the screen edge. .edgesIgnoringSafeArea(.top) ) } diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index e67d4b08..0e7b79c0 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.8' + spec.version = '9.0.9' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkickmobile.com' } diff --git a/SwiftMessages/KeyboardTrackingView.swift b/SwiftMessages/KeyboardTrackingView.swift index 301d969c..f3c0ad95 100644 --- a/SwiftMessages/KeyboardTrackingView.swift +++ b/SwiftMessages/KeyboardTrackingView.swift @@ -72,6 +72,7 @@ open class KeyboardTrackingView: UIView { private var isAutomaticallyPaused = false private var heightConstraint: NSLayoutConstraint! + private var lastObservedKeyboardRect: CGRect? private func postInit() { translatesAutoresizingMaskIntoConstraints = false @@ -109,15 +110,19 @@ open class KeyboardTrackingView: UIView { isAutomaticallyPaused = false } + open override func layoutSubviews() { + super.layoutSubviews() + heightConstraint.constant = calculateHeightConstant() + } + private func show(change: Change, _ notification: Notification) { guard !(isPaused || isAutomaticallyPaused), let userInfo = (notification as NSNotification).userInfo, let value = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return } willChange(change: change, userInfo: userInfo) delegate?.keyboardTrackingViewWillChange(change: change, userInfo: userInfo) - let keyboardRect = value.cgRectValue - let thisRect = convert(bounds, to: nil) - let newHeight = max(0, thisRect.maxY - keyboardRect.minY) + topMargin + lastObservedKeyboardRect = value.cgRectValue + let newHeight = calculateHeightConstant() guard heightConstraint.constant != newHeight else { return } animateKeyboardChange(change: change, height: newHeight, userInfo: userInfo) } @@ -140,4 +145,10 @@ open class KeyboardTrackingView: UIView { CATransaction.commit() } } + + private func calculateHeightConstant() -> CGFloat { + guard let keyboardRect = lastObservedKeyboardRect else { return 0 } + let thisRect = convert(bounds, to: nil) + return max(0, thisRect.maxY - keyboardRect.minY) + topMargin + } } diff --git a/SwiftMessages/MessageHostingView.swift b/SwiftMessages/MessageHostingView.swift index d7bb5f1e..489ab96a 100644 --- a/SwiftMessages/MessageHostingView.swift +++ b/SwiftMessages/MessageHostingView.swift @@ -39,4 +39,12 @@ public class MessageHostingView: BaseView, Identifiable where Content: required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } + + public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let view = super.hitTest(point, with: event) + // The rendered SwiftUI view isn't a direct child of this hosting view. SwiftUI + // inserts another intermediate view that should also ignore touches. + if view == self || view?.superview == self { return nil } + return view + } } diff --git a/SwiftUIDemo/SwiftUIDemo/DemoMessage.swift b/SwiftUIDemo/SwiftUIDemo/DemoMessage.swift index ccc86b66..32624de1 100644 --- a/SwiftUIDemo/SwiftUIDemo/DemoMessage.swift +++ b/SwiftUIDemo/SwiftUIDemo/DemoMessage.swift @@ -11,12 +11,13 @@ import SwiftMessages struct DemoMessage: Identifiable { let title: String let body: String + let style: DemoMessageView.Style var id: String { title + body } } extension DemoMessage: MessageViewConvertible { func asMessageView() -> DemoMessageView { - DemoMessageView(message: self) + DemoMessageView(message: self, style: style) } } diff --git a/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift index a299c356..53963023 100644 --- a/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift +++ b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift @@ -7,11 +7,20 @@ import SwiftUI +// A card-style message view struct DemoMessageView: View { // MARK: - API + enum Style { + case standard + case card + case tab + } + let message: DemoMessage + let style: Style + // MARK: - Variables @@ -20,21 +29,42 @@ struct DemoMessageView: View { // MARK: - Body var body: some View { + switch style { + case .standard: + content() + // Mask the content and extend background into the safe area. + .mask { + Rectangle() + .edgesIgnoringSafeArea(.top) + } + case .card: + content() + // Mask the content with a rounded rectangle + .mask { + RoundedRectangle(cornerRadius: 15) + } + // External padding around the card + .padding(10) + case .tab: + content() + // Mask the content with rounded bottom edge and extend background into the safe area. + .mask { + UnevenRoundedRectangle(bottomLeadingRadius: 15, bottomTrailingRadius: 15) + .edgesIgnoringSafeArea(.top) + } + } + } + + @ViewBuilder private func content() -> some View { VStack(alignment: .leading) { Text(message.title).font(.system(size: 20, weight: .bold)) Text(message.body) } .multilineTextAlignment(.leading) + // Internal padding of the card .padding(30) + // Greedy width .frame(maxWidth: .infinity) .background(.demoMessageBackground) - // This makes a tab-style view where the bottom corners are rounded and the view's background - // extends to the top edge. - .mask( - UnevenRoundedRectangle( - cornerRadii: .init(bottomLeading: 15, bottomTrailing: 15) - ) - .edgesIgnoringSafeArea(.top) - ) } } diff --git a/SwiftUIDemo/SwiftUIDemo/DemoView.swift b/SwiftUIDemo/SwiftUIDemo/DemoView.swift index a6736d89..8f47b7df 100644 --- a/SwiftUIDemo/SwiftUIDemo/DemoView.swift +++ b/SwiftUIDemo/SwiftUIDemo/DemoView.swift @@ -13,10 +13,30 @@ struct DemoView: View { @State var message: DemoMessage? var body: some View { - Button("Show message") { - message = DemoMessage(title: "Demo", body: "This is a sample SwiftUI message! This content should be long enough to wrap.") + VStack { + Button("Show standard message") { + message = DemoMessage( + title: "Demo", + body: "This is a sample SwiftUI card-style message! This content should be long enough to wrap.", + style: .standard + ) + } + Button("Show card message") { + message = DemoMessage( + title: "Demo", + body: "This is a sample SwiftUI card-style message! This content should be long enough to wrap.", + style: .card + ) + } + Button("Show tab message") { + message = DemoMessage( + title: "Demo", + body: "This is a sample SwiftUI card-style message! This content should be long enough to wrap.", + style: .tab + ) + } } - .buttonBorderShape(.roundedRectangle(radius: 15)) + .buttonStyle(.bordered) .swiftMessage(message: $message) } } From 95f65d57f018a18ec352c6bf7fde1a6e3c4550c9 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sun, 3 Dec 2023 10:41:56 -0600 Subject: [PATCH 121/139] #534 Fix warnings? --- SwiftMessages/BaseView.swift | 10 +-- .../MarginAdjustable+Extensions.swift | 21 +----- SwiftMessages/PhysicsAnimation.swift | 4 +- SwiftMessages/Presenter.swift | 65 ++++++++----------- SwiftMessages/TopBottomAnimation.swift | 4 +- 5 files changed, 35 insertions(+), 69 deletions(-) diff --git a/SwiftMessages/BaseView.swift b/SwiftMessages/BaseView.swift index e5aa7b9c..c41d166b 100644 --- a/SwiftMessages/BaseView.swift +++ b/SwiftMessages/BaseView.swift @@ -280,6 +280,11 @@ open class BaseView: UIView, BackgroundViewable, MarginAdjustable { private var layoutConstraints: [NSLayoutConstraint] = [] private var regularWidthLayoutConstraints: [NSLayoutConstraint] = [] + + open override func layoutSubviews() { + super.layoutSubviews() + updateShadowPath() + } } /* @@ -334,11 +339,6 @@ extension BaseView { // Update the layer's `shadowPath` without animation layer.shadowPath = shadowPath } } - - open override func layoutSubviews() { - super.layoutSubviews() - updateShadowPath() - } } /* diff --git a/SwiftMessages/MarginAdjustable+Extensions.swift b/SwiftMessages/MarginAdjustable+Extensions.swift index b6277885..da8f46d1 100644 --- a/SwiftMessages/MarginAdjustable+Extensions.swift +++ b/SwiftMessages/MarginAdjustable+Extensions.swift @@ -13,25 +13,8 @@ extension MarginAdjustable where Self: UIView { var layoutMargins: UIEdgeInsets = layoutMarginAdditions var safeAreaInsets: UIEdgeInsets = { guard respectSafeArea else { return .zero } - if #available(iOS 11, *) { - insetsLayoutMarginsFromSafeArea = false - return self.safeAreaInsets - } else { - #if SWIFTMESSAGES_APP_EXTENSIONS - let application: UIApplication? = nil - #else - let application: UIApplication? = UIApplication.shared - #endif - if !context.safeZoneConflicts.isDisjoint(with: [.statusBar]), - let app = application, - app.statusBarOrientation == .portrait || app.statusBarOrientation == .portraitUpsideDown { - let frameInWindow = convert(bounds, to: window) - let top = max(0, 20 - frameInWindow.minY) - return UIEdgeInsets(top: top, left: 0, bottom: 0, right: 0) - } else { - return .zero - } - } + insetsLayoutMarginsFromSafeArea = false + return self.safeAreaInsets }() if !context.safeZoneConflicts.isDisjoint(with: .overStatusBar) { safeAreaInsets.top = 0 diff --git a/SwiftMessages/PhysicsAnimation.swift b/SwiftMessages/PhysicsAnimation.swift index 0fb976c5..c073fe4a 100644 --- a/SwiftMessages/PhysicsAnimation.swift +++ b/SwiftMessages/PhysicsAnimation.swift @@ -93,9 +93,7 @@ public class PhysicsAnimation: NSObject, Animator { guard let adjustable = messageView as? MarginAdjustable & UIView, let context = context else { return } adjustable.preservesSuperviewLayoutMargins = false - if #available(iOS 11, *) { - adjustable.insetsLayoutMarginsFromSafeArea = false - } + adjustable.insetsLayoutMarginsFromSafeArea = false adjustable.layoutMargins = adjustable.defaultMarginAdjustment(context: context) } diff --git a/SwiftMessages/Presenter.swift b/SwiftMessages/Presenter.swift index 5a3648b8..44f92015 100644 --- a/SwiftMessages/Presenter.swift +++ b/SwiftMessages/Presenter.swift @@ -236,7 +236,7 @@ class Presenter: NSObject { } private func safeZoneConflicts() -> SafeZoneConflicts { - guard let window = maskingView.window else { return [] } + guard let _ = maskingView.window else { return [] } let windowLevel: UIWindow.Level = { if let vc = presentationContext.viewControllerValue() as? WindowViewController { return vc.config.windowLevel ?? .normal @@ -253,47 +253,34 @@ class Presenter: NSObject { if let vc = presentationContext.viewControllerValue() as? UITabBarController { return vc.sm_isVisible(view: vc.tabBar) } return false }() - if #available(iOS 11, *) { - if windowLevel > .normal { - // TODO seeing `maskingView.safeAreaInsets.top` value of 20 on - // iPhone 8 with status bar window level. This seems like an iOS bug since - // the message view's window is above the status bar. Applying a special rule - // to allow the animator to revove this amount from the layout margins if needed. - // This may need to be reworked if any future device has a legitimate 20pt top safe area, - // such as with a potentially smaller notch. - if maskingView.safeAreaInsets.top == 20 { - return [.overStatusBar] - } else { - var conflicts: SafeZoneConflicts = [] - if maskingView.safeAreaInsets.top > 0 { - conflicts.formUnion(.sensorNotch) - } - if maskingView.safeAreaInsets.bottom > 0 { - conflicts.formUnion(.homeIndicator) - } - return conflicts + if windowLevel > .normal { + // TODO seeing `maskingView.safeAreaInsets.top` value of 20 on + // iPhone 8 with status bar window level. This seems like an iOS bug since + // the message view's window is above the status bar. Applying a special rule + // to allow the animator to revove this amount from the layout margins if needed. + // This may need to be reworked if any future device has a legitimate 20pt top safe area, + // such as with a potentially smaller notch. + if maskingView.safeAreaInsets.top == 20 { + return [.overStatusBar] + } else { + var conflicts: SafeZoneConflicts = [] + if maskingView.safeAreaInsets.top > 0 { + conflicts.formUnion(.sensorNotch) } + if maskingView.safeAreaInsets.bottom > 0 { + conflicts.formUnion(.homeIndicator) + } + return conflicts } - var conflicts: SafeZoneConflicts = [] - if !underNavigationBar { - conflicts.formUnion(.sensorNotch) - } - if !underTabBar { - conflicts.formUnion(.homeIndicator) - } - return conflicts - } else { - #if SWIFTMESSAGES_APP_EXTENSIONS - return [] - #else - if UIApplication.shared.isStatusBarHidden { return [] } - if (windowLevel > UIWindow.Level.normal) || underNavigationBar { return [] } - let statusBarFrame = UIApplication.shared.statusBarFrame - let statusBarWindowFrame = window.convert(statusBarFrame, from: nil) - let statusBarViewFrame = maskingView.convert(statusBarWindowFrame, from: nil) - return statusBarViewFrame.intersects(maskingView.bounds) ? SafeZoneConflicts.statusBar : [] - #endif } + var conflicts: SafeZoneConflicts = [] + if !underNavigationBar { + conflicts.formUnion(.sensorNotch) + } + if !underTabBar { + conflicts.formUnion(.homeIndicator) + } + return conflicts } private func getPresentationContext() throws -> PresentationContext { diff --git a/SwiftMessages/TopBottomAnimation.swift b/SwiftMessages/TopBottomAnimation.swift index 21b0f271..a0d440c7 100644 --- a/SwiftMessages/TopBottomAnimation.swift +++ b/SwiftMessages/TopBottomAnimation.swift @@ -130,9 +130,7 @@ public class TopBottomAnimation: NSObject, Animator { guard let adjustable = messageView as? MarginAdjustable & UIView, let context = context else { return } adjustable.preservesSuperviewLayoutMargins = false - if #available(iOS 11, *) { - adjustable.insetsLayoutMarginsFromSafeArea = false - } + adjustable.insetsLayoutMarginsFromSafeArea = false var layoutMargins = adjustable.defaultMarginAdjustment(context: context) switch style { case .top: From 633b6e593b5730daf9e682cd21f50764bd1e257c Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sun, 3 Dec 2023 11:54:25 -0600 Subject: [PATCH 122/139] #535 Remove needless async code --- Package.swift | 2 +- SwiftMessages.podspec | 4 +- SwiftMessages.xcodeproj/project.pbxproj | 16 +- .../xcschemes/SwiftMessages.xcscheme | 2 +- SwiftMessages/KeyboardTrackingView.swift | 13 +- SwiftMessages/Presenter.swift | 2 + SwiftMessages/SwiftMessageModifier.swift | 2 +- SwiftMessages/SwiftMessages.swift | 167 +++++++----------- SwiftMessages/Task+Extensions.swift | 15 ++ 9 files changed, 105 insertions(+), 118 deletions(-) create mode 100644 SwiftMessages/Task+Extensions.swift diff --git a/Package.swift b/Package.swift index a0f30e8b..a906ba1a 100644 --- a/Package.swift +++ b/Package.swift @@ -4,7 +4,7 @@ import PackageDescription let package = Package( name: "SwiftMessages", platforms: [ - .iOS("9.0") + .iOS("13.0") ], products: [ .library(name: "SwiftMessages", targets: ["SwiftMessages"]), diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index 0e7b79c0..b2b0e4ff 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -6,9 +6,9 @@ Pod::Spec.new do |spec| spec.authors = { 'Timothy Moose' => 'tim@swiftkickmobile.com' } spec.summary = 'A very flexible message bar for iOS written in Swift.' spec.source = {:git => 'https://github.com/SwiftKickMobile/SwiftMessages.git', :tag => spec.version} - spec.platform = :ios, '12.0' + spec.platform = :ios, '13.0' spec.swift_version = '5.0' - spec.ios.deployment_target = '12.0' + spec.ios.deployment_target = '13.0' spec.framework = 'UIKit' spec.requires_arc = true spec.default_subspec = 'App' diff --git a/SwiftMessages.xcodeproj/project.pbxproj b/SwiftMessages.xcodeproj/project.pbxproj index 45809f2d..19d5bcd0 100644 --- a/SwiftMessages.xcodeproj/project.pbxproj +++ b/SwiftMessages.xcodeproj/project.pbxproj @@ -59,6 +59,7 @@ 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2061EE480D000E2DDC1 /* Animator.swift */; }; 2298C2091EE486E300E2DDC1 /* TopBottomAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */; }; 229F778125FAB1E9008C2ACB /* UIWindow+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */; }; + 22D3B4562B1CEF76002D8665 /* Task+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22D3B4552B1CEF76002D8665 /* Task+Extensions.swift */; }; 22DFC9161EFF30F6001B1CA1 /* CenteredView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */; }; 22DFC9181F00674E001B1CA1 /* PhysicsPanHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */; }; 22E01F641E74EC8B00ACE19A /* MaskingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22E01F631E74EC8B00ACE19A /* MaskingView.swift */; }; @@ -151,6 +152,7 @@ 2298C2081EE486E300E2DDC1 /* TopBottomAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBottomAnimation.swift; sourceTree = ""; }; 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Extensions.swift"; sourceTree = ""; }; 22A2EA6E24EC6CFA00BB2540 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + 22D3B4552B1CEF76002D8665 /* Task+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Task+Extensions.swift"; sourceTree = ""; }; 22DFC9151EFF30F6001B1CA1 /* CenteredView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CenteredView.xib; path = Resources/CenteredView.xib; sourceTree = ""; }; 22DFC9171F00674E001B1CA1 /* PhysicsPanHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsPanHandler.swift; sourceTree = ""; }; 22E01F631E74EC8B00ACE19A /* MaskingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaskingView.swift; sourceTree = ""; }; @@ -220,6 +222,7 @@ 220655111FAF82B600F4E00F /* MarginAdjustable+Extensions.swift */, 22774B9F20B5EF2A00813732 /* UIEdgeInsets+Extensions.swift */, 229F778025FAB1E9008C2ACB /* UIWindow+Extensions.swift */, + 22D3B4552B1CEF76002D8665 /* Task+Extensions.swift */, ); name = Extensions; sourceTree = ""; @@ -453,7 +456,7 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 1500; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = "SwiftKick Mobile"; TargetAttributes = { 86B48AEB1D5A41C900063E2B = { @@ -556,6 +559,7 @@ 22F27951210CE25900273E7F /* CornerRoundingView.swift in Sources */, 86BBA9011D5E040600FE8F16 /* PassthroughWindow.swift in Sources */, 2298C2071EE480D000E2DDC1 /* Animator.swift in Sources */, + 22D3B4562B1CEF76002D8665 /* Task+Extensions.swift in Sources */, 86BBA9031D5E040600FE8F16 /* UIViewController+Extensions.swift in Sources */, 228F7DDF2ACF703A006C9644 /* SwiftMessageModifier.swift in Sources */, 224FB69921153B440081D4DE /* CALayer+Extensions.swift in Sources */, @@ -609,6 +613,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -655,7 +660,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -668,6 +673,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -708,7 +714,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; @@ -732,7 +738,7 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -767,7 +773,7 @@ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INFOPLIST_FILE = SwiftMessages/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme b/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme index 5c84455f..ba0f414b 100644 --- a/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme +++ b/SwiftMessages.xcodeproj/xcshareddata/xcschemes/SwiftMessages.xcscheme @@ -1,6 +1,6 @@ ) case view(_: Weak) diff --git a/SwiftMessages/SwiftMessageModifier.swift b/SwiftMessages/SwiftMessageModifier.swift index 479b6d91..9974e8b6 100644 --- a/SwiftMessages/SwiftMessageModifier.swift +++ b/SwiftMessages/SwiftMessageModifier.swift @@ -47,7 +47,7 @@ private struct SwiftMessageModifier: ViewModifier where Message: Messag content .onChange(of: message) { _ in if let message { - let show: (SwiftMessages.Config, UIView) -> Void = swiftMessages?.show(config:view:) ?? SwiftMessages.show(config:view:) + let show: @MainActor (SwiftMessages.Config, UIView) -> Void = swiftMessages?.show(config:view:) ?? SwiftMessages.show(config:view:) let view = MessageHostingView(message: message) var config = config ?? swiftMessages?.defaultConfig ?? SwiftMessages.defaultConfig config.eventListeners.append { event in diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index 395bc0ad..52244eff 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor private let globalInstance = SwiftMessages() /** @@ -15,6 +16,7 @@ private let globalInstance = SwiftMessages() It behaves like a queue, only showing one message at a time. Message views that adopt the `Identifiable` protocol (as `MessageView` does) will have duplicates removed. */ +@MainActor open class SwiftMessages { /** @@ -396,9 +398,7 @@ open class SwiftMessages { */ open func show(config: Config, view: UIView) { let presenter = Presenter(config: config, view: view, delegate: self) - messageQueue.sync { - enqueue(presenter: presenter) - } + enqueue(presenter: presenter) } /** @@ -425,11 +425,11 @@ open class SwiftMessages { - Parameter config: The configuration options. - Parameter viewProvider: A block that returns the view to be displayed. */ - open func show(config: Config, viewProvider: @escaping ViewProvider) { - DispatchQueue.main.async { [weak self] in - guard let strongSelf = self else { return } + nonisolated open func show(config: Config, viewProvider: @escaping ViewProvider) { + Task { @MainActor [weak self] in + guard let self else { return } let view = viewProvider() - strongSelf.show(config: config, view: view) + self.show(config: config, view: view) } } @@ -451,9 +451,7 @@ open class SwiftMessages { Hide the current message being displayed by animating it away. */ open func hide(animated: Bool = true) { - messageQueue.sync { - hideCurrent(animated: animated) - } + hideCurrent(animated: animated) } /** @@ -461,12 +459,10 @@ open class SwiftMessages { clear the message queue. */ open func hideAll() { - messageQueue.sync { - queue.removeAll() - delays.removeAll() - counts.removeAll() - hideCurrent() - } + queue.removeAll() + delays.removeAll() + counts.removeAll() + hideCurrent() } /** @@ -476,14 +472,12 @@ open class SwiftMessages { - Parameter id: The identifier of the message to remove. */ open func hide(id: String) { - messageQueue.sync { - if id == _current?.id { - hideCurrent() - } - queue = queue.filter { $0.id != id } - delays.remove(id: id) - counts[id] = nil + if id == _current?.id { + hideCurrent() } + queue = queue.filter { $0.id != id } + delays.remove(id: id) + counts[id] = nil } /** @@ -492,21 +486,19 @@ open class SwiftMessages { shown from multiple code paths to ensure that all paths are ready to hide. */ open func hideCounted(id: String) { - messageQueue.sync { - if let count = counts[id] { - if count < 2 { - counts[id] = nil - } else { - counts[id] = count - 1 - return - } - } - if id == _current?.id { - hideCurrent() + if let count = counts[id] { + if count < 2 { + counts[id] = nil + } else { + counts[id] = count - 1 + return } - queue = queue.filter { $0.id != id } - delays.remove(id: id) } + if id == _current?.id { + hideCurrent() + } + queue = queue.filter { $0.id != id } + delays.remove(id: id) } /** @@ -538,6 +530,7 @@ open class SwiftMessages { open var pauseBetweenMessages: TimeInterval = 0.5 /// Type for keeping track of delayed presentations + @MainActor fileprivate class Delays { fileprivate func add(presenter: Presenter) { @@ -563,20 +556,17 @@ open class SwiftMessages { } func show(presenter: Presenter) { - messageQueue.sync { - enqueue(presenter: presenter) - } + enqueue(presenter: presenter) } - fileprivate let messageQueue = DispatchQueue(label: "it.swiftkick.SwiftMessages", attributes: []) fileprivate var queue: [Presenter] = [] fileprivate var delays = Delays() fileprivate var counts: [String : Int] = [:] fileprivate var _current: Presenter? = nil { didSet { if oldValue != nil { - let delayTime = DispatchTime.now() + pauseBetweenMessages - messageQueue.asyncAfter(deadline: delayTime) { [weak self] in + Task { [weak self] in + try? await Task.sleep(seconds: self?.pauseBetweenMessages ?? 0) self?.dequeueNext() } } @@ -598,9 +588,10 @@ open class SwiftMessages { } if let delay = presenter.delayShow { delays.add(presenter: presenter) - messageQueue.asyncAfter(deadline: .now() + delay) { [weak self] in + Task { [weak self] in + try? await Task.sleep(seconds: delay) // Don't enqueue if the view has been hidden during the delay window. - guard let strongSelf = self, strongSelf.delays.remove(presenter: presenter) else { return } + guard let self, self.delays.remove(presenter: presenter) else { return } doEnqueue() } } else { @@ -618,26 +609,19 @@ open class SwiftMessages { // block on animation completion. self.autohideToken = current current.showDate = CACurrentMediaTime() - DispatchQueue.main.async { [weak self] in - guard let strongSelf = self else { return } - do { - try current.show { completed in - guard let strongSelf = self else { return } - guard completed else { - strongSelf.messageQueue.sync { - strongSelf.internalHide(presenter: current) - } - return - } - if current === strongSelf.autohideToken { - strongSelf.queueAutoHide() - } + do { + try current.show { [weak self] completed in + guard let self else { return } + guard completed else { + self.internalHide(presenter: current) + return } - } catch { - strongSelf.messageQueue.sync { - strongSelf._current = nil + if current === self.autohideToken { + self.queueAutoHide() } } + } catch { + _current = nil } } @@ -654,16 +638,15 @@ open class SwiftMessages { guard let current = _current, !current.isHiding else { return } let action = { [weak self] in current.hide(animated: animated) { (completed) in - guard completed, let strongSelf = self else { return } - strongSelf.messageQueue.sync { - guard strongSelf._current === current else { return } - strongSelf.counts[current.id] = nil - strongSelf._current = nil - } + guard completed, let self else { return } + guard self._current === current else { return } + self.counts[current.id] = nil + self._current = nil } } let delay = current.delayHide ?? 0 - DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + Task { + try? await Task.sleep(seconds: delay) action() } } @@ -674,18 +657,20 @@ open class SwiftMessages { guard let current = _current else { return } autohideToken = current if let pauseDuration = current.pauseDuration { - let delayTime = DispatchTime.now() + pauseDuration - messageQueue.asyncAfter(deadline: delayTime, execute: { + Task { [weak self] in + try? await Task.sleep(seconds: pauseDuration) // Make sure we've still got a green light to auto-hide. - if self.autohideToken !== current { return } + guard let self, self.autohideToken !== current else { return } self.internalHide(presenter: current) - }) + } } } deinit { - // Prevent orphaned messages - hideCurrent() + guard let current = _current else { return } + Task { @MainActor [current] in + current.hide(animated: true) { _ in } + } } } @@ -701,11 +686,7 @@ extension SwiftMessages { - Returns: The view of type `T` if it is currently being shown or hidden. */ public func current() -> T? { - var view: T? - messageQueue.sync { - view = _current?.view as? T - } - return view + _current?.view as? T } /** @@ -715,13 +696,7 @@ extension SwiftMessages { - Returns: The view with matching id if currently being shown or hidden. */ public func current(id: String) -> T? { - var view: T? - messageQueue.sync { - if let current = _current, current.id == id { - view = current.view as? T - } - } - return view + _current?.id == id ? _current?.view as? T : nil } /** @@ -731,13 +706,7 @@ extension SwiftMessages { - Returns: The view with matching id if currently queued to be shown. */ public func queued(id: String) -> T? { - var view: T? - messageQueue.sync { - if let queued = queue.first(where: { $0.id == id }) { - view = queued.view as? T - } - } - return view + queue.first { $0.id == id }?.view as? T } /** @@ -759,16 +728,12 @@ extension SwiftMessages { extension SwiftMessages: PresenterDelegate { func hide(presenter: Presenter) { - messageQueue.sync { - self.internalHide(presenter: presenter) - } + self.internalHide(presenter: presenter) } public func hide(animator: Animator) { - messageQueue.sync { - guard let presenter = self.presenter(forAnimator: animator) else { return } - self.internalHide(presenter: presenter) - } + guard let presenter = self.presenter(forAnimator: animator) else { return } + self.internalHide(presenter: presenter) } public func panStarted(animator: Animator) { @@ -898,7 +863,7 @@ extension SwiftMessages { globalInstance.show(viewProvider: viewProvider) } - public static func show(config: Config, viewProvider: @escaping ViewProvider) { + nonisolated public static func show(config: Config, viewProvider: @escaping ViewProvider) { globalInstance.show(config: config, viewProvider: viewProvider) } diff --git a/SwiftMessages/Task+Extensions.swift b/SwiftMessages/Task+Extensions.swift new file mode 100644 index 00000000..9d6f1c3f --- /dev/null +++ b/SwiftMessages/Task+Extensions.swift @@ -0,0 +1,15 @@ +// +// Task+Extensions.swift +// SwiftMessages +// +// Created by Timothy Moose on 12/3/23. +// Copyright Β© 2023 SwiftKick Mobile. All rights reserved. +// + +import Foundation + +extension Task where Success == Never, Failure == Never { + static func sleep(seconds: TimeInterval) async throws { + try await sleep(nanoseconds: UInt64(seconds * 1_000_000_000)) + } +} From 5ff2cb30766d7b153bb60b29338e095a0cfd3e38 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sun, 3 Dec 2023 12:03:14 -0600 Subject: [PATCH 123/139] Remove a couple of more usages of dispatch queues --- SwiftMessages/Animator.swift | 1 + SwiftMessages/PhysicsAnimation.swift | 1 + SwiftMessages/PhysicsPanHandler.swift | 5 ++++- SwiftMessages/SwiftMessagesSegue.swift | 3 ++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/SwiftMessages/Animator.swift b/SwiftMessages/Animator.swift index 82074068..346ce2f8 100644 --- a/SwiftMessages/Animator.swift +++ b/SwiftMessages/Animator.swift @@ -58,6 +58,7 @@ public class AnimationContext { } } +@MainActor public protocol Animator: AnyObject { /// Adopting classes should declare as `weak`. diff --git a/SwiftMessages/PhysicsAnimation.swift b/SwiftMessages/PhysicsAnimation.swift index c073fe4a..5f5ecaf0 100644 --- a/SwiftMessages/PhysicsAnimation.swift +++ b/SwiftMessages/PhysicsAnimation.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor public class PhysicsAnimation: NSObject, Animator { public enum Placement { diff --git a/SwiftMessages/PhysicsPanHandler.swift b/SwiftMessages/PhysicsPanHandler.swift index da82fc18..e381d22d 100644 --- a/SwiftMessages/PhysicsPanHandler.swift +++ b/SwiftMessages/PhysicsPanHandler.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor open class PhysicsPanHandler { public var hideDelay: TimeInterval = 0.2 @@ -17,6 +18,7 @@ open class PhysicsPanHandler { var time: CFAbsoluteTime } + @MainActor public final class State { weak var messageView: UIView? @@ -127,7 +129,8 @@ open class PhysicsPanHandler { let frame = containerView.convert(view.bounds, from: view) if !containerView.bounds.intersects(frame) { self.isOffScreen = true - DispatchQueue.main.asyncAfter(deadline: .now() + self.hideDelay) { + Task { + try? await Task.sleep(seconds: self.hideDelay) animator.delegate?.hide(animator: animator) } } diff --git a/SwiftMessages/SwiftMessagesSegue.swift b/SwiftMessages/SwiftMessagesSegue.swift index cd17eec3..35687e14 100644 --- a/SwiftMessages/SwiftMessagesSegue.swift +++ b/SwiftMessages/SwiftMessagesSegue.swift @@ -228,7 +228,8 @@ open class SwiftMessagesSegue: UIStoryboardSegue { /// is removed without first dismissing. This monitor handles that scenario by setting `self.selfRetainer = nil` if /// the presenting view controller is no longer in the heirarchy. private func startReleaseMonitor() { - DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in + Task { @MainActor [weak self] in + try? await Task.sleep(seconds: 2) guard let self = self else { return } switch self.source.view.window { case .none: self.selfRetainer = nil From f3555f04126e93af1bcc5c64fa351bfb38d6740c Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Sun, 3 Dec 2023 12:17:07 -0600 Subject: [PATCH 124/139] Fix typo --- SwiftMessages/SwiftMessages.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftMessages/SwiftMessages.swift b/SwiftMessages/SwiftMessages.swift index 52244eff..1245f067 100644 --- a/SwiftMessages/SwiftMessages.swift +++ b/SwiftMessages/SwiftMessages.swift @@ -651,7 +651,7 @@ open class SwiftMessages { } } - fileprivate weak var autohideToken: AnyObject? + fileprivate weak var autohideToken: Presenter? fileprivate func queueAutoHide() { guard let current = _current else { return } @@ -660,7 +660,7 @@ open class SwiftMessages { Task { [weak self] in try? await Task.sleep(seconds: pauseDuration) // Make sure we've still got a green light to auto-hide. - guard let self, self.autohideToken !== current else { return } + guard let self, self.autohideToken == current else { return } self.internalHide(presenter: current) } } From e70fb07baae07e3dca3da2ce7a8d497bfd472b20 Mon Sep 17 00:00:00 2001 From: Timothy Moose Date: Mon, 15 Jan 2024 15:20:12 -0600 Subject: [PATCH 125/139] Add sheet like variation on swiftMessage modifier --- CHANGELOG.md | 12 +++ README.md | 47 +++++++---- SwiftMessages.podspec | 2 +- SwiftMessages/MessageHostingView.swift | 11 ++- SwiftMessages/SwiftMessageModifier.swift | 41 ++++++++-- .../SwiftUIDemo.xcodeproj/project.pbxproj | 4 + SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift | 2 +- .../DemoMessageWithButtonView.swift | 77 +++++++++++++++++++ SwiftUIDemo/SwiftUIDemo/DemoView.swift | 19 +++++ 9 files changed, 190 insertions(+), 25 deletions(-) create mode 100644 SwiftUIDemo/SwiftUIDemo/DemoMessageWithButtonView.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f5cc826..6031c135 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Change Log All notable changes to this project will be documented in this file. +## 9.0.10 + +### Features + +* Add a `.sheet()` like variation to the `.swiftMessage()` modifier that takes a view builder. This provides more flexibility for constructing message views. + +### Fixes + +* #535 window being accessed from background thread when dequeueNext is called +* #534 Xcode warnings in two swift files +* #533 How do I show a message that appears above the keyboard, when the keyboard is already visible? + ## 9.0.9 ### Fixes diff --git a/README.md b/README.md index 5af94cb4..6a6f5afe 100644 --- a/README.md +++ b/README.md @@ -178,8 +178,7 @@ And check out our blog post [Elegant Custom UIViewController Transitioning](http Any of the built-in SwiftMessages views can be displayed by calling the SwiftMessages APIs from within observable object, a button action closure, etc. However, SwiftMessages can also display your custom SwiftUI views. -The first step is to define a type that conforms to `MessageViewConvertible`. This would typically be a struct containing the message data to display: - +Take the following message view and companion data model: ````swift struct DemoMessage: Identifiable { @@ -189,12 +188,6 @@ struct DemoMessage: Identifiable { var id: String { title + body } } -extension DemoMessage: MessageViewConvertible { - func asMessageView() -> DemoMessageView { - DemoMessageView(message: self) - } -} - struct DemoMessageView: View { let message: DemoMessage @@ -212,7 +205,7 @@ struct DemoMessageView: View { // This makes a tab-style view where the bottom corners are rounded and // the view's background extends to the top edge. .mask( - UnevenRoundedRectangle(bottomLeadingRadius: 15, bottomTrailingRadius: 15) + UnevenRoundedRectangle(bottomLeadingRadius: 15, bottomTrailingRadius: 15) // This causes the background to extend into the safe area to the screen edge. .edgesIgnoringSafeArea(.top) ) @@ -220,14 +213,14 @@ struct DemoMessageView: View { } ```` -The SwiftUI message view can be displayed just like any other UIKit message by using `MessageHostingView`: +You can show it from a button action, view model or other similar context like: ````swift struct DemoView: View { var body: some View { Button("Show message") { let message = DemoMessage(title: "Demo", body: "SwiftUI forever!") - let messageView = MessageHostingView(message: message) + let messageView = MessageHostingView(id: message.id, content: DemoMessageView(message: message) SwiftMessages.show(view: messageView) } } @@ -245,12 +238,40 @@ struct DemoView: View { Button("Show message") { message = DemoMessage(title: "Demo", body: "SwiftUI forever!") } - .swiftMessage(message: $message) + .swiftMessage(message: $message) { message in + DemoMessageView(message: message) + } } } ```` -This technique may be more SwiftUI-like, but it doesn't offer the full capability of SwiftMessages, such as explicitly hiding messages by their ID. It is totally reasonable to use a combination of both approaches. +This is very similar to the `.sheet()` modifier. However, it doesn't expose all of the features of SwiftMessages, such as explicitly hiding messages by ID. It is totally reasonable to use a combination of both approaches. + +If your message views are purely data-driven and don't require delegates, callbacks, etc., there is a slightly simplified variation on `swiftMessage()` that doesn't require a view builder. Instead, your data model should conform to `MessageViewConvertible`. + +````swift +extension DemoMessage: MessageViewConvertible { + func asMessageView() -> DemoMessageView { + DemoMessageView(message: self) + } +} +```` + +Then you can drop the view builder when calling `swiftMessage()`: + +````swift +struct DemoView: View { + + @State var message: DemoMessage? + + var body: some View { + Button("Show message") { + message = DemoMessage(title: "Demo", body: "SwiftUI forever!") + } + .swiftMessage(message: $message) + } +} +```` Try it out in the SwiftUI demo app! diff --git a/SwiftMessages.podspec b/SwiftMessages.podspec index b2b0e4ff..8042309b 100644 --- a/SwiftMessages.podspec +++ b/SwiftMessages.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'SwiftMessages' - spec.version = '9.0.9' + spec.version = '9.0.10' spec.license = { :type => 'MIT' } spec.homepage = 'https://github.com/SwiftKickMobile/SwiftMessages' spec.authors = { 'Timothy Moose' => 'tim@swiftkickmobile.com' } diff --git a/SwiftMessages/MessageHostingView.swift b/SwiftMessages/MessageHostingView.swift index 489ab96a..b295669e 100644 --- a/SwiftMessages/MessageHostingView.swift +++ b/SwiftMessages/MessageHostingView.swift @@ -16,10 +16,9 @@ public class MessageHostingView: BaseView, Identifiable where Content: public let id: String - public init(message: Message) where Message: MessageViewConvertible, Message.Content == Content { - let messageView: Content = message.asMessageView() - hostVC = UIHostingController(rootView: messageView) - id = message.id + public init(id: String, content: Content) { + hostVC = UIHostingController(rootView: content) + self.id = id super.init(frame: .zero) hostVC.loadViewIfNeeded() installContentView(hostVC.view) @@ -27,6 +26,10 @@ public class MessageHostingView: BaseView, Identifiable where Content: hostVC.view.backgroundColor = .clear } + convenience public init(message: Message) where Message: MessageViewConvertible, Message.Content == Content { + self.init(id: message.id, content: message.asMessageView() ) + } + // MARK: - Constants // MARK: - Variables diff --git a/SwiftMessages/SwiftMessageModifier.swift b/SwiftMessages/SwiftMessageModifier.swift index 9974e8b6..56f40f2c 100644 --- a/SwiftMessages/SwiftMessageModifier.swift +++ b/SwiftMessages/SwiftMessageModifier.swift @@ -9,28 +9,56 @@ import SwiftUI @available(iOS 14.0, *) public extension View { - /// A state-based modifier for displaying a message. + /// A state-based modifier for displaying a message when `Message` does not conform to `MessageViewConvertible`. This variant is more flexible and + /// should be used if the message view can't be represented as pure data, such as if it requires a delegate, has callbacks, etc. + func swiftMessage( + message: Binding, + config: SwiftMessages.Config? = nil, + swiftMessages: SwiftMessages? = nil, + @ViewBuilder messageContent: @escaping (Message) -> MessageContent + ) -> some View where Message: Equatable & Identifiable, MessageContent: View { + modifier(SwiftMessageModifier(message: message, config: config, swiftMessages: swiftMessages, messageContent: messageContent)) + } + + /// A state-based modifier for displaying a message when `Message` conforms to `MessageViewConvertible`. This variant should be used if the message + /// view can be represented as pure data. If the message requires a delegate, has callbacks, etc., consider using the variant that takes a message view builder. func swiftMessage( message: Binding, config: SwiftMessages.Config? = nil, swiftMessages: SwiftMessages? = nil ) -> some View where Message: MessageViewConvertible { - modifier(SwiftMessageModifier(message: message, config: config, swiftMessages: swiftMessages)) + swiftMessage(message: message, config: config, swiftMessages: swiftMessages) { content in + content.asMessageView() + } } } @available(iOS 14.0, *) -private struct SwiftMessageModifier: ViewModifier where Message: MessageViewConvertible { +private struct SwiftMessageModifier: ViewModifier where Message: Equatable & Identifiable, MessageContent: View { + // MARK: - API fileprivate init( message: Binding, config: SwiftMessages.Config? = nil, - swiftMessages: SwiftMessages? = nil + swiftMessages: SwiftMessages? = nil, + @ViewBuilder messageContent: @escaping (Message) -> MessageContent ) { _message = message self.config = config self.swiftMessages = swiftMessages + self.messageContent = messageContent + } + + fileprivate init( + message: Binding, + config: SwiftMessages.Config? = nil, + swiftMessages: SwiftMessages? = nil + ) where Message: MessageViewConvertible, Message.Content == MessageContent { + _message = message + self.config = config + self.swiftMessages = swiftMessages + self.messageContent = { $0.asMessageView() } } // MARK: - Constants @@ -40,15 +68,16 @@ private struct SwiftMessageModifier: ViewModifier where Message: Messag @Binding private var message: Message? private let config: SwiftMessages.Config? private let swiftMessages: SwiftMessages? + @ViewBuilder private let messageContent: (Message) -> MessageContent // MARK: - Body func body(content: Content) -> some View { content - .onChange(of: message) { _ in + .onChange(of: message) { message in if let message { let show: @MainActor (SwiftMessages.Config, UIView) -> Void = swiftMessages?.show(config:view:) ?? SwiftMessages.show(config:view:) - let view = MessageHostingView(message: message) + let view = MessageHostingView(id: message.id, content: messageContent(message)) var config = config ?? swiftMessages?.defaultConfig ?? SwiftMessages.defaultConfig config.eventListeners.append { event in if case .didHide = event, event.id == self.message?.id { diff --git a/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj index f6c945bc..790676b5 100644 --- a/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj +++ b/SwiftUIDemo/SwiftUIDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 22549DC02B55CFE8005E3E21 /* DemoMessageWithButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22549DBF2B55CFE8005E3E21 /* DemoMessageWithButtonView.swift */; }; 228F7DAD2ACF17E8006C9644 /* SwiftUIDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DAC2ACF17E8006C9644 /* SwiftUIDemoApp.swift */; }; 228F7DAF2ACF17E8006C9644 /* DemoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 228F7DAE2ACF17E8006C9644 /* DemoView.swift */; }; 228F7DB12ACF17E9006C9644 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 228F7DB02ACF17E9006C9644 /* Assets.xcassets */; }; @@ -49,6 +50,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 22549DBF2B55CFE8005E3E21 /* DemoMessageWithButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoMessageWithButtonView.swift; sourceTree = ""; }; 228F7DA92ACF17E8006C9644 /* SwiftUIDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 228F7DAC2ACF17E8006C9644 /* SwiftUIDemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIDemoApp.swift; sourceTree = ""; }; 228F7DAE2ACF17E8006C9644 /* DemoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoView.swift; sourceTree = ""; }; @@ -102,6 +104,7 @@ 228F7DAE2ACF17E8006C9644 /* DemoView.swift */, 228F7DD42ACF59E4006C9644 /* DemoMessage.swift */, 228F7DD62ACF5C2E006C9644 /* DemoMessageView.swift */, + 22549DBF2B55CFE8005E3E21 /* DemoMessageWithButtonView.swift */, 228F7DB02ACF17E9006C9644 /* Assets.xcassets */, 228F7DB22ACF17E9006C9644 /* Preview Content */, ); @@ -230,6 +233,7 @@ 228F7DD72ACF5C2E006C9644 /* DemoMessageView.swift in Sources */, 228F7DAF2ACF17E8006C9644 /* DemoView.swift in Sources */, 228F7DAD2ACF17E8006C9644 /* SwiftUIDemoApp.swift in Sources */, + 22549DC02B55CFE8005E3E21 /* DemoMessageWithButtonView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift index 53963023..11cf9611 100644 --- a/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift +++ b/SwiftUIDemo/SwiftUIDemo/DemoMessageView.swift @@ -7,7 +7,7 @@ import SwiftUI -// A card-style message view +// A message view with a title and message. struct DemoMessageView: View { // MARK: - API diff --git a/SwiftUIDemo/SwiftUIDemo/DemoMessageWithButtonView.swift b/SwiftUIDemo/SwiftUIDemo/DemoMessageWithButtonView.swift new file mode 100644 index 00000000..e74172ef --- /dev/null +++ b/SwiftUIDemo/SwiftUIDemo/DemoMessageWithButtonView.swift @@ -0,0 +1,77 @@ +// +// DemoMessageWithButtonView.swift +// SwiftUIDemo +// +// Created by Timothy Moose on 1/15/24. +// + +import SwiftUI + +// A message view with a title, message and button. +struct DemoMessageWithButtonView