From b3987e54e71b0c69c5e1d238bf7d01b4af4db3a9 Mon Sep 17 00:00:00 2001 From: Jacob Farkas Date: Sat, 31 Oct 2020 23:13:00 -0700 Subject: [PATCH] Update cocoapods --- Podfile | 6 +- Podfile.lock | 28 +- Pods/Interpolate/README.md | 2 +- Pods/Local Podspecs/Interpolate.podspec.json | 27 - Pods/Local Podspecs/NapySlider.podspec.json | 20 - Pods/Manifest.lock | 28 +- Pods/MarqueeLabel/README.mdown | 51 +- Pods/MarqueeLabel/Sources/MarqueeLabel.swift | 1874 +++++++++++++++++ Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.h | 500 ----- Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.m | 1682 --------------- Pods/NapySlider/NapySlider/NapySlider.swift | 86 +- Pods/NapySlider/README.md | 2 - Pods/Pods.xcodeproj/project.pbxproj | 969 ++++----- .../BASSGaplessAudioPlayer.debug.xcconfig | 13 + .../BASSGaplessAudioPlayer.release.xcconfig | 13 + .../Interpolate/Interpolate-Info.plist | 2 +- .../Interpolate/Interpolate.debug.xcconfig | 13 + .../Interpolate/Interpolate.release.xcconfig | 13 + .../MarqueeLabel/MarqueeLabel-Info.plist | 2 +- .../MarqueeLabel/MarqueeLabel-umbrella.h | 1 - .../MarqueeLabel/MarqueeLabel.debug.xcconfig | 13 + .../MarqueeLabel.release.xcconfig | 13 + .../NapySlider/NapySlider.debug.xcconfig | 12 + .../NapySlider/NapySlider.release.xcconfig | 12 + .../Pods-AGAudioPlayer-frameworks.sh | 96 +- .../Pods-AGAudioPlayer.debug.xcconfig | 3 + .../Pods-AGAudioPlayer.release.xcconfig | 3 + 27 files changed, 2590 insertions(+), 2894 deletions(-) delete mode 100644 Pods/Local Podspecs/Interpolate.podspec.json delete mode 100644 Pods/Local Podspecs/NapySlider.podspec.json create mode 100644 Pods/MarqueeLabel/Sources/MarqueeLabel.swift delete mode 100755 Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.h delete mode 100755 Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.m create mode 100644 Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.debug.xcconfig create mode 100644 Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.release.xcconfig create mode 100644 Pods/Target Support Files/Interpolate/Interpolate.debug.xcconfig create mode 100644 Pods/Target Support Files/Interpolate/Interpolate.release.xcconfig create mode 100644 Pods/Target Support Files/MarqueeLabel/MarqueeLabel.debug.xcconfig create mode 100644 Pods/Target Support Files/MarqueeLabel/MarqueeLabel.release.xcconfig create mode 100644 Pods/Target Support Files/NapySlider/NapySlider.debug.xcconfig create mode 100644 Pods/Target Support Files/NapySlider/NapySlider.release.xcconfig diff --git a/Podfile b/Podfile index f9ea29b..ef3d014 100644 --- a/Podfile +++ b/Podfile @@ -1,15 +1,13 @@ -# Uncomment this line to define a global platform for your project -source 'https://github.com/CocoaPods/Specs.git' inhibit_all_warnings! use_frameworks! target "AGAudioPlayer" do platform :ios, '11.0' - pod 'Interpolate', :path => '../Interpolate' + pod 'Interpolate' pod 'BASSGaplessAudioPlayer', :path => '../gapless-audio-bass-ios' pod 'MarqueeLabel' - pod 'NapySlider', :path => '../NapySlider' + pod 'NapySlider' # pod 'HysteriaPlayer', :head end diff --git a/Podfile.lock b/Podfile.lock index e161154..6911f17 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,35 +1,31 @@ PODS: - BASSGaplessAudioPlayer (0.0.1) - - Interpolate (1.2.1) - - MarqueeLabel (3.2.1): - - MarqueeLabel/ObjC (= 3.2.1) - - MarqueeLabel/ObjC (3.2.1) + - Interpolate (1.3.0) + - MarqueeLabel (4.0.5) - NapySlider (0.3.6) DEPENDENCIES: - BASSGaplessAudioPlayer (from `../gapless-audio-bass-ios`) - - Interpolate (from `../Interpolate`) + - Interpolate - MarqueeLabel - - NapySlider (from `../NapySlider`) + - NapySlider SPEC REPOS: - https://github.com/cocoapods/specs.git: + trunk: + - Interpolate - MarqueeLabel + - NapySlider EXTERNAL SOURCES: BASSGaplessAudioPlayer: :path: "../gapless-audio-bass-ios" - Interpolate: - :path: "../Interpolate" - NapySlider: - :path: "../NapySlider" SPEC CHECKSUMS: BASSGaplessAudioPlayer: 5b074495769769192b720c70aa2a60f6f33751f3 - Interpolate: 090ee71b9bac8a926ed7f60512c6bfdb9fb921e5 - MarqueeLabel: 2daf039bf916937c8a4c9adfc13577cc5e51b4ce - NapySlider: faba6c6695ca3e2a4e00846eb3e906bc8e896a13 + Interpolate: 99edce3f72d84d1b9fdc3f769c775b6ade7f92e9 + MarqueeLabel: 00cc0bcd087111dca575878b3531af980559707d + NapySlider: 433c06071e7029d1dea13bf4ca25a79b584b103a -PODFILE CHECKSUM: ab4d7fcaddb47d7bcf2f85b200288e7ea3805492 +PODFILE CHECKSUM: f3c80db68d203b893769535681a00c9037da6d5f -COCOAPODS: 1.7.0.beta.1 +COCOAPODS: 1.10.0 diff --git a/Pods/Interpolate/README.md b/Pods/Interpolate/README.md index 457c809..7cd3794 100644 --- a/Pods/Interpolate/README.md +++ b/Pods/Interpolate/README.md @@ -126,7 +126,7 @@ In fact, you can easily create and use your own interpolation function - all you ### Setting up with [CocoaPods](http://cocoapods.org/?q=Interpolate) ```ruby source 'https://github.com/CocoaPods/Specs.git' -pod 'Interpolate', '~> 1.2.0' +pod 'Interpolate', '~> 1.3.0' ``` ### Setting up with Carthage diff --git a/Pods/Local Podspecs/Interpolate.podspec.json b/Pods/Local Podspecs/Interpolate.podspec.json deleted file mode 100644 index f120a1e..0000000 --- a/Pods/Local Podspecs/Interpolate.podspec.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "Interpolate", - "version": "1.2.1", - "summary": "Swift interpolation framework for gesture-driven animations.", - "description": "Interpolate is a Swift interpolation framework for creating interactive gesture-driven animations..", - "homepage": "https://github.com/marmelroy/Interpolate", - "license": "MIT", - "authors": { - "Roy Marmelstein": "marmelroy@gmail.com" - }, - "source": { - "git": "https://github.com/marmelroy/Interpolate.git", - "tag": "1.2.1" - }, - "social_media_url": "http://twitter.com/marmelroy", - "platforms": { - "ios": "8.0", - "tvos": "9.0" - }, - "requires_arc": true, - "swift_versions": "4.2", - "source_files": "Interpolate", - "frameworks": [ - "QuartzCore", - "Foundation" - ] -} diff --git a/Pods/Local Podspecs/NapySlider.podspec.json b/Pods/Local Podspecs/NapySlider.podspec.json deleted file mode 100644 index 539c6b1..0000000 --- a/Pods/Local Podspecs/NapySlider.podspec.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "NapySlider", - "version": "0.3.6", - "summary": "A vertical slider UIControl element written in swift.", - "homepage": "https://github.com/seeppp/NapySlider", - "license": "MIT", - "authors": { - "Jonas Schoch": "jonas.schoch@naptics.ch" - }, - "source": { - "git": "https://github.com/seeppp/NapySlider.git", - "tag": "0.3.6" - }, - "platforms": { - "ios": "8.4" - }, - "swift_versions": "5.0", - "requires_arc": true, - "source_files": "NapySlider/NapySlider.swift" -} diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index e161154..6911f17 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -1,35 +1,31 @@ PODS: - BASSGaplessAudioPlayer (0.0.1) - - Interpolate (1.2.1) - - MarqueeLabel (3.2.1): - - MarqueeLabel/ObjC (= 3.2.1) - - MarqueeLabel/ObjC (3.2.1) + - Interpolate (1.3.0) + - MarqueeLabel (4.0.5) - NapySlider (0.3.6) DEPENDENCIES: - BASSGaplessAudioPlayer (from `../gapless-audio-bass-ios`) - - Interpolate (from `../Interpolate`) + - Interpolate - MarqueeLabel - - NapySlider (from `../NapySlider`) + - NapySlider SPEC REPOS: - https://github.com/cocoapods/specs.git: + trunk: + - Interpolate - MarqueeLabel + - NapySlider EXTERNAL SOURCES: BASSGaplessAudioPlayer: :path: "../gapless-audio-bass-ios" - Interpolate: - :path: "../Interpolate" - NapySlider: - :path: "../NapySlider" SPEC CHECKSUMS: BASSGaplessAudioPlayer: 5b074495769769192b720c70aa2a60f6f33751f3 - Interpolate: 090ee71b9bac8a926ed7f60512c6bfdb9fb921e5 - MarqueeLabel: 2daf039bf916937c8a4c9adfc13577cc5e51b4ce - NapySlider: faba6c6695ca3e2a4e00846eb3e906bc8e896a13 + Interpolate: 99edce3f72d84d1b9fdc3f769c775b6ade7f92e9 + MarqueeLabel: 00cc0bcd087111dca575878b3531af980559707d + NapySlider: 433c06071e7029d1dea13bf4ca25a79b584b103a -PODFILE CHECKSUM: ab4d7fcaddb47d7bcf2f85b200288e7ea3805492 +PODFILE CHECKSUM: f3c80db68d203b893769535681a00c9037da6d5f -COCOAPODS: 1.7.0.beta.1 +COCOAPODS: 1.10.0 diff --git a/Pods/MarqueeLabel/README.mdown b/Pods/MarqueeLabel/README.mdown index a1a713d..4b60a88 100644 --- a/Pods/MarqueeLabel/README.mdown +++ b/Pods/MarqueeLabel/README.mdown @@ -3,7 +3,11 @@ Overview MarqueeLabel is a UILabel subclass adds a scrolling marquee effect when the text of the label outgrows the available width. The label scrolling direction and speed/rate can be specified as well. All standard UILabel properties (where it makes sense) are available in MarqueeLabel, with the intent of MarqueeLabel behaving just like a UILabel. -MarqueeLabel is compatible with both iOS and tvOS, and currently works with Swift 3.0 and the iOS 10.0 SDK! (But if you're looking for Swift 2.x compatibility, [you can use release 2.8](https://github.com/cbpowell/MarqueeLabel/releases/tag/2.8.0)) +**MarqueeLabel will be maintained in Swift _only_ starting with [release 4.0](https://github.com/cbpowell/MarqueeLabel/releases/tag/4.0.0)!** + +MarqueeLabel is compatible with both iOS and tvOS, and currently works with Swift 5.0 and the iOS 12.2 SDK! (But if you're looking for prior version Swift compatibility, [you can check the older releases](https://github.com/cbpowell/MarqueeLabel/releases/)) + + ## Check it out! ![GIF of MarqueeLabelDemo in action](https://raw.githubusercontent.com/cbpowell/MarqueeLabel/master/Metadata/MarqueeLabelDemo.gif) @@ -19,16 +23,10 @@ MarqueeLabel is compatible with both iOS and tvOS, and currently works with Swif ### Installation #### [CocoaPods](http://cocoapods.org) -MarqueeLabel has [subspecs](https://guides.cocoapods.org/syntax/podspec.html#subspec) for both Objective-C and Swift! Currently, Objective-C is the default subspec. - -That means to use MarqueeLabel in an Objective-C project, add the following to your project's Podfile: +To use MarqueeLabel in a project, add the following to your project's Podfile: ```ruby pod 'MarqueeLabel' ``` -But if you're using Swift, add the following instead to specify the Swift subspec: -```ruby -pod 'MarqueeLabel/Swift' -``` #### Carthage @@ -39,7 +37,7 @@ github "cbpowell/MarqueeLabel" #### Manual Installation -1. Add MarqueeLabel.h and MarqueeLabel.m, or MarqueeLabel.swift, to your project. +1. Add MarqueeLabel.swift, to your project. 2. Add **QuartzCore.framework** to your project frameworks. 3. Import MarqueeLabel and replace your UILabels with MarqueeLabels as needed. @@ -66,16 +64,6 @@ See the included demo project for several use case examples! ### Code These lines of code create a MarqueeLabel that will scroll across its content in 8.0 seconds, and adds 10.0 point long fade at the left and right boundaries. -#### Objective-C -Replace: - - UILabel *lengthyLabel = [[UILabel alloc] initWithFrame:aFrame]; - -With: - - MarqueeLabel *lengthyLabel = [[MarqueeLabel alloc] initWithFrame:aFrame duration:8.0 andFadeLength:10.0f]; - -#### Swift Replace: var lengthyLabel = UILabel.init(frame:aFrame) @@ -100,7 +88,7 @@ Check out the [MarqueeLabel documentation](http://cocoadocs.org/docsets/MarqueeL ## Extras -Also check out [the Extras folder](/Extras), a collection of subclasses, extensions, and modifications for MarqueeLabel to implement various functionality that has been requested or suggested, but not merged into the MarqueeLabel code. +Also check out [the Extras folder](/Extras), a collection of subclasses, extensions, and modifications for MarqueeLabel to implement various functionality that has been requested or suggested, but not merged into the MarqueeLabel code. ## Special Notes @@ -140,29 +128,10 @@ To make sure the scrolling animation _does_ begin as the cell scrolls onscreen, #### Important Animation Note MarqueeLabel is based on Core Animation, which does cause some problems when views appear and disappear and the repeating animation is stopped by iOS and does not automatically restart. -To address this, MarqueeLabel provides a few class methods that allow easy "restarting" of all MarqueeLabels associated with a UIViewController. Specifically, the class method `restartLabelsOfController:` should be called by your view controller (which passes in `self` for the `controller` parameter) when it is revealed or about to be revealed. Keep in mind that presenting a modal view controller can pause repeating UIView animations in the controller that is being covered! +To address this, MarqueeLabel provides a few class methods that allow easy "restarting" of all MarqueeLabels associated with a UIViewController. Specifically, the class method `restartLabelsOfController:` should be called by your view controller (which passes in `self` for the `controller` parameter) when it is revealed or about to be revealed. Keep in mind that presenting a modal view controller can pause repeating UIView animations in the controller that is being covered! `controllerLabelsShouldLabelize:` and `controllerLabelsShouldAnimate:` are for convenience, allowing labelizing and re-animating all labels of a UIViewController. Labelizing can be useful for performance, such as labelizing all MarqueeLabels when a UITableView/UIScrollView starts scrolling. -#### Using MarqueeLabel as a dependency with Cocoapods and Carthage - Swift only! - -If you're developing your own Swift framework that uses MarqueeLabel as a dependency, and want to support both Cocoapods _and_ Carthage, you may need to do a little extra work. Because of the current naming of MarqueeLabel frameworks (and Carthage building all targets in the project), the name of Swift dynamic framework to import varies between Cocoapods and Carthage. - -When building the Swift subspec with Cocoapods, MarqueeLabel is imported with `import MarqueeLabel`. However, because Carthage requires distinct names for each target, when building with Carthage the import statement for the Swift target is `import MarqueeLabelSwift`. - -A suggested workaround is to use a [conditional compilation block](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-ID538) (aka preprocessor macro) to switch between the two import statements based on whether or not the target is intended for use with Carthage. To specify the target, you can add an "Other Swift Flag" in the Swift Compiler - Custom Flags section of your Carthage target (i.e. the framework) build settings: - - - -And then include the following conditional compilation statement to use the appropriate framework name: -```swift -#if CARTHAGE_CONFIG - import MarqueeLabelSwift //Carthage build name -#else - import MarqueeLabel // Cocoapods build name -#endif -``` - ## Todo - Ideas? @@ -173,4 +142,6 @@ Charles Powell - [GitHub](http://github.com/cbpowell) - [Twitter](http://twitter.com/seventhcolumn) +Buy Me A Coffee + Give me a shout if you're using this in your project! diff --git a/Pods/MarqueeLabel/Sources/MarqueeLabel.swift b/Pods/MarqueeLabel/Sources/MarqueeLabel.swift new file mode 100644 index 0000000..31e4769 --- /dev/null +++ b/Pods/MarqueeLabel/Sources/MarqueeLabel.swift @@ -0,0 +1,1874 @@ +// +// MarqueeLabel.swift +// +// Created by Charles Powell on 8/6/14. +// Copyright (c) 2015 Charles Powell. All rights reserved. +// + +import UIKit +import QuartzCore + +@IBDesignable + +open class MarqueeLabel: UILabel, CAAnimationDelegate { + + /** + An enum that defines the types of `MarqueeLabel` scrolling + + - Left: Scrolls left after the specified delay, and does not return to the original position. + - LeftRight: Scrolls left first, then back right to the original position. + - Right: Scrolls right after the specified delay, and does not return to the original position. + - RightLeft: Scrolls right first, then back left to the original position. + - Continuous: Continuously scrolls left (with a pause at the original position if animationDelay is set). + - ContinuousReverse: Continuously scrolls right (with a pause at the original position if animationDelay is set). + */ + public enum MarqueeType { + case left + case leftRight + case right + case rightLeft + case continuous + case continuousReverse + } + + // + // MARK: - Public properties + // + + /** + Defines the direction and method in which the `MarqueeLabel` instance scrolls. + `MarqueeLabel` supports six default types of scrolling: `Left`, `LeftRight`, `Right`, `RightLeft`, `Continuous`, and `ContinuousReverse`. + + Given the nature of how text direction works, the options for the `type` property require specific text alignments + and will set the textAlignment property accordingly. + + - `LeftRight` and `Left` types are ONLY compatible with a label text alignment of `NSTextAlignment.left`. + - `RightLeft` and `Right` types are ONLY compatible with a label text alignment of `NSTextAlignment.right`. + - `Continuous` and `ContinuousReverse` allow the use of `NSTextAlignment.left`, `.right`, or `.center` alignments, + however the text alignment only has an effect when label text is short enough that scrolling is not required. + When scrolling, the labels are effectively center-aligned. + + Defaults to `Continuous`. + + - Note: Note that any `leadingBuffer` value will affect the text alignment location relative to the frame position, + including with `.center` alignment, where the center alignment location will be shifted left (for `.continuous`) or + right (for `.continuousReverse`) by one-half (1/2) the `.leadingBuffer` amount. Use the `.trailingBuffer` property to + add a buffer between text "loops" without affecting alignment location. + + - SeeAlso: textAlignment + - SeeAlso: leadingBuffer + */ + open var type: MarqueeType = .continuous { + didSet { + if type == oldValue { + return + } + updateAndScroll() + } + } + + /** + An optional custom scroll "sequence", defined by an array of `ScrollStep` or `FadeStep` instances. A sequence + defines a single scroll/animation loop, which will continue to be automatically repeated like the default types. + + A `type` value is still required when using a custom sequence. The `type` value defines the `home` and `away` + values used in the `ScrollStep` instances, and the `type` value determines which way the label will scroll. + + When a custom sequence is not supplied, the default sequences are used per the defined `type`. + + `ScrollStep` steps are the primary step types, and define the position of the label at a given time in the sequence. + `FadeStep` steps are secondary steps that define the edge fade state (leading, trailing, or both) around the `ScrollStep` + steps. + + Defaults to nil. + + - Attention: Use of the `scrollSequence` property requires understanding of how MarqueeLabel works for effective + use. As a reference, it is suggested to review the methodology used to build the sequences for the default types. + + - SeeAlso: type + - SeeAlso: ScrollStep + - SeeAlso: FadeStep + */ + open var scrollSequence: [MarqueeStep]? + + /** + Specifies the animation curve used in the scrolling motion of the labels. + Allowable options: + + - `UIViewAnimationOptionCurveEaseInOut` + - `UIViewAnimationOptionCurveEaseIn` + - `UIViewAnimationOptionCurveEaseOut` + - `UIViewAnimationOptionCurveLinear` + + Defaults to `UIViewAnimationOptionCurveEaseInOut`. + */ + open var animationCurve: UIView.AnimationCurve = .linear + + /** + A boolean property that sets whether the `MarqueeLabel` should behave like a normal `UILabel`. + + When set to `true` the `MarqueeLabel` will behave and look like a normal `UILabel`, and will not begin any scrolling animations. + Changes to this property take effect immediately, removing any in-flight animation as well as any edge fade. Note that `MarqueeLabel` + will respect the current values of the `lineBreakMode` and `textAlignment`properties while labelized. + + To simply prevent automatic scrolling, use the `holdScrolling` property. + + Defaults to `false`. + + - SeeAlso: holdScrolling + - SeeAlso: lineBreakMode + - Note: The label will not automatically scroll when this property is set to `true`. + - Warning: The UILabel default setting for the `lineBreakMode` property is `NSLineBreakByTruncatingTail`, which truncates + the text adds an ellipsis glyph (...). Set the `lineBreakMode` property to `NSLineBreakByClipping` in order to avoid the + ellipsis, especially if using an edge transparency fade. + */ + @IBInspectable open var labelize: Bool = false { + didSet { + if labelize != oldValue { + updateAndScroll() + } + } + } + + /** + A boolean property that sets whether the `MarqueeLabel` should hold (prevent) automatic label scrolling. + + When set to `true`, `MarqueeLabel` will not automatically scroll even its text is larger than the specified frame, + although the specified edge fades will remain. + + To set `MarqueeLabel` to act like a normal UILabel, use the `labelize` property. + + Defaults to `false`. + + - Note: The label will not automatically scroll when this property is set to `true`. + - SeeAlso: labelize + */ + @IBInspectable open var holdScrolling: Bool = false { + didSet { + if holdScrolling != oldValue { + if oldValue == true && !(awayFromHome || labelize ) && labelShouldScroll() { + updateAndScroll() + } + } + } + } + + /** + A boolean property that sets whether the `MarqueeLabel` should only begin a scroll when tapped. + + If this property is set to `true`, the `MarqueeLabel` will only begin a scroll animation cycle when tapped. The label will + not automatically being a scroll. This setting overrides the setting of the `holdScrolling` property. + + Defaults to `false`. + + - Note: The label will not automatically scroll when this property is set to `false`. + - SeeAlso: holdScrolling + */ + @IBInspectable open var tapToScroll: Bool = false { + didSet { + if tapToScroll != oldValue { + if tapToScroll { + let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(MarqueeLabel.labelWasTapped(_:))) + self.addGestureRecognizer(tapRecognizer) + isUserInteractionEnabled = true + } else { + if let recognizer = self.gestureRecognizers!.first as UIGestureRecognizer? { + self.removeGestureRecognizer(recognizer) + } + isUserInteractionEnabled = false + } + } + } + } + + /** + A read-only boolean property that indicates if the label's scroll animation has been paused. + + - SeeAlso: pauseLabel + - SeeAlso: unpauseLabel + */ + open var isPaused: Bool { + return (sublabel.layer.speed == 0.0) + } + + /** + A boolean property that indicates if the label is currently away from the home location. + + The "home" location is the traditional location of `UILabel` text. This property essentially reflects if a scroll animation is underway. + */ + open var awayFromHome: Bool { + if let presentationLayer = sublabel.layer.presentation() { + return !(presentationLayer.position.x == homeLabelFrame.origin.x) + } + + return false + } + + /** + The `MarqueeLabel` scrolling speed may be defined by one of two ways: + - Rate(CGFloat): The speed is defined by a rate of motion, in units of points per second. + - Duration(CGFloat): The speed is defined by the time to complete a scrolling animation cycle, in units of seconds. + + Each case takes an associated `CGFloat` value, which is the rate/duration desired. + */ + public enum SpeedLimit { + case rate(CGFloat) + case duration(CGFloat) + + var value: CGFloat { + switch self { + case .rate(let rate): + return rate + case .duration(let duration): + return duration + } + } + } + + /** + Defines the speed of the `MarqueeLabel` scrolling animation. + + The speed is set by specifying a case of the `SpeedLimit` enum along with an associated value. + + - SeeAlso: SpeedLimit + */ + open var speed: SpeedLimit = .duration(7.0) { + didSet { + switch (speed, oldValue) { + case (.rate(let a), .rate(let b)) where a == b: + return + case (.duration(let a), .duration(let b)) where a == b: + return + default: + updateAndScroll() + } + } + } + + @available(*, deprecated, message: "Use speed property instead") + @IBInspectable open var scrollDuration: CGFloat { + get { + switch speed { + case .duration(let duration): return duration + case .rate(_): return 0.0 + } + } + set { + speed = .duration(newValue) + } + } + + @available(*, deprecated, message : "Use speed property instead") + @IBInspectable open var scrollRate: CGFloat { + get { + switch speed { + case .duration(_): return 0.0 + case .rate(let rate): return rate + } + } + set { + speed = .rate(newValue) + } + } + + + /** + A buffer (offset) between the leading edge of the label text and the label frame. + + This property adds additional space between the leading edge of the label text and the label frame. The + leading edge is the edge of the label text facing the direction of scroll (i.e. the edge that animates + offscreen first during scrolling). + + Defaults to `0`. + + - Note: The value set to this property affects label positioning at all times (including when `labelize` is set to `true`), + including when the text string length is short enough that the label does not need to scroll. + - Note: For Continuous-type labels, the smallest value of `leadingBuffer`, `trailingBuffer`, and `fadeLength` + is used as spacing between the two label instances. Zero is an allowable value for all three properties. + + - SeeAlso: trailingBuffer + */ + @IBInspectable open var leadingBuffer: CGFloat = 0.0 { + didSet { + if leadingBuffer != oldValue { + updateAndScroll() + } + } + } + + /** + A buffer (offset) between the trailing edge of the label text and the label frame. + + This property adds additional space (buffer) between the trailing edge of the label text and the label frame. The + trailing edge is the edge of the label text facing away from the direction of scroll (i.e. the edge that animates + offscreen last during scrolling). + + Defaults to `0`. + + - Note: The value set to this property has no effect when the `labelize` property is set to `true`. + + - Note: For Continuous-type labels, the smallest value of `leadingBuffer`, `trailingBuffer`, and `fadeLength` + is used as spacing between the two label instances. Zero is an allowable value for all three properties. + + - SeeAlso: leadingBuffer + */ + @IBInspectable open var trailingBuffer: CGFloat = 0.0 { + didSet { + if trailingBuffer != oldValue { + updateAndScroll() + } + } + } + + /** + The length of transparency fade at the left and right edges of the frame. + + This propery sets the size (in points) of the view edge transparency fades on the left and right edges of a `MarqueeLabel`. The + transparency fades from an alpha of 1.0 (fully visible) to 0.0 (fully transparent) over this distance. Values set to this property + will be sanitized to prevent a fade length greater than 1/2 of the frame width. + + Defaults to `0`. + */ + @IBInspectable open var fadeLength: CGFloat = 0.0 { + didSet { + if fadeLength != oldValue { + applyGradientMask(fadeLength, animated: true) + updateAndScroll() + } + } + } + + + /** + The length of delay in seconds that the label pauses at the completion of a scroll. + */ + @IBInspectable open var animationDelay: CGFloat = 1.0 + + + /** The read-only/computed duration of the scroll animation (not including delay). + + The value of this property is calculated from the value set to the `speed` property. If a duration-type speed is + used to set the label animation speed, `animationDuration` will be equivalent to that value. + */ + public var animationDuration: CGFloat { + switch self.speed { + case .rate(let rate): + return CGFloat(abs(self.awayOffset) / rate) + case .duration(let duration): + return duration + } + } + + // + // MARK: - Class Functions and Helpers + // + + /** + Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + - Parameter controller: The view controller for which to restart all `MarqueeLabel` instances. + + - Warning: View controllers that appear with animation (such as from underneath a modal-style controller) can cause some `MarqueeLabel` text + position "jumping" when this method is used in `viewDidAppear` if scroll animations are already underway. Use this method inside `viewWillAppear:` + instead to avoid this problem. + + - Warning: This method may not function properly if passed the parent view controller when using view controller containment. + + - SeeAlso: restartLabel + - SeeAlso: controllerViewDidAppear: + - SeeAlso: controllerViewWillAppear: + */ + open class func restartLabelsOfController(_ controller: UIViewController) { + MarqueeLabel.notifyController(controller, message: .Restart) + } + + /** + Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + Alternative to `restartLabelsOfController`. This method is retained for backwards compatibility and future enhancements. + + - Parameter controller: The view controller that will appear. + - SeeAlso: restartLabel + - SeeAlso: controllerViewDidAppear + */ + open class func controllerViewWillAppear(_ controller: UIViewController) { + MarqueeLabel.restartLabelsOfController(controller) + } + + /** + Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + Alternative to `restartLabelsOfController`. This method is retained for backwards compatibility and future enhancements. + + - Parameter controller: The view controller that did appear. + - SeeAlso: restartLabel + - SeeAlso: controllerViewWillAppear + */ + open class func controllerViewDidAppear(_ controller: UIViewController) { + MarqueeLabel.restartLabelsOfController(controller) + } + + /** + Labelizes all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + The `labelize` property of all recognized `MarqueeLabel` instances will be set to `true`. + + - Parameter controller: The view controller for which all `MarqueeLabel` instances should be labelized. + - SeeAlso: labelize + */ + open class func controllerLabelsLabelize(_ controller: UIViewController) { + MarqueeLabel.notifyController(controller, message: .Labelize) + } + + /** + De-labelizes all `MarqueeLabel` instances that have the specified view controller in their next responder chain. + + The `labelize` property of all recognized `MarqueeLabel` instances will be set to `false`. + + - Parameter controller: The view controller for which all `MarqueeLabel` instances should be de-labelized. + - SeeAlso: labelize + */ + open class func controllerLabelsAnimate(_ controller: UIViewController) { + MarqueeLabel.notifyController(controller, message: .Animate) + } + + + // + // MARK: - Initialization + // + + /** + Returns a newly initialized `MarqueeLabel` instance with the specified scroll rate and edge transparency fade length. + + - Parameter frame: A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. + - Parameter pixelsPerSec: A rate of scroll for the label scroll animation. Must be non-zero. Note that this will be the peak (mid-transition) rate for ease-type animation. + - Parameter fadeLength: A length of transparency fade at the left and right edges of the `MarqueeLabel` instance's frame. + - Returns: An initialized `MarqueeLabel` object or nil if the object couldn't be created. + - SeeAlso: fadeLength + */ + public init(frame: CGRect, rate: CGFloat, fadeLength fade: CGFloat) { + speed = .rate(rate) + fadeLength = CGFloat(min(fade, frame.size.width/2.0)) + super.init(frame: frame) + setup() + } + + /** + Returns a newly initialized `MarqueeLabel` instance with the specified scroll rate and edge transparency fade length. + + - Parameter frame: A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. + - Parameter scrollDuration: A scroll duration the label scroll animation. Must be non-zero. This will be the duration that the animation takes for one-half of the scroll cycle in the case of left-right and right-left marquee types, and for one loop of a continuous marquee type. + - Parameter fadeLength: A length of transparency fade at the left and right edges of the `MarqueeLabel` instance's frame. + - Returns: An initialized `MarqueeLabel` object or nil if the object couldn't be created. + - SeeAlso: fadeLength + */ + public init(frame: CGRect, duration: CGFloat, fadeLength fade: CGFloat) { + speed = .duration(duration) + fadeLength = CGFloat(min(fade, frame.size.width/2.0)) + super.init(frame: frame) + setup() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setup() + } + + /** + Returns a newly initialized `MarqueeLabel` instance. + + The default scroll duration of 7.0 seconds and fade length of 0.0 are used. + + - Parameter frame: A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. + - Returns: An initialized `MarqueeLabel` object or nil if the object couldn't be created. + */ + convenience public override init(frame: CGRect) { + self.init(frame: frame, duration:7.0, fadeLength:0.0) + } + + private func setup() { + // Create sublabel + sublabel = UILabel(frame: self.bounds) + sublabel.tag = 700 + sublabel.layer.anchorPoint = CGPoint.zero + + // Add sublabel + addSubview(sublabel) + + // Configure self + super.clipsToBounds = true + super.numberOfLines = 1 + + // Add notification observers + // Custom class notifications + NotificationCenter.default.addObserver(self, selector: #selector(MarqueeLabel.restartForViewController(_:)), name: NSNotification.Name(rawValue: MarqueeKeys.Restart.rawValue), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(MarqueeLabel.labelizeForController(_:)), name: NSNotification.Name(rawValue: MarqueeKeys.Labelize.rawValue), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(MarqueeLabel.animateForController(_:)), name: NSNotification.Name(rawValue: MarqueeKeys.Animate.rawValue), object: nil) + // UIApplication state notifications + NotificationCenter.default.addObserver(self, selector: #selector(MarqueeLabel.restartLabel), name: UIApplication.didBecomeActiveNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(MarqueeLabel.shutdownLabel), name: UIApplication.didEnterBackgroundNotification, object: nil) + } + + override open func awakeFromNib() { + super.awakeFromNib() + forwardPropertiesToSublabel() + } + + @available(iOS 8.0, *) + override open func prepareForInterfaceBuilder() { + super.prepareForInterfaceBuilder() + forwardPropertiesToSublabel() + } + + private func forwardPropertiesToSublabel() { + /* + Note that this method is currently ONLY called from awakeFromNib, i.e. when + text properties are set via a Storyboard. As the Storyboard/IB doesn't currently + support attributed strings, there's no need to "forward" the super attributedString value. + */ + + // Since we're a UILabel, we actually do implement all of UILabel's properties. + // We don't care about these values, we just want to forward them on to our sublabel. + let properties = ["baselineAdjustment", "enabled", "highlighted", "highlightedTextColor", + "minimumFontSize", "shadowOffset", "textAlignment", + "userInteractionEnabled", "adjustsFontSizeToFitWidth", + "lineBreakMode", "numberOfLines", "contentMode"] + + // Iterate through properties + sublabel.text = super.text + sublabel.font = super.font + sublabel.textColor = super.textColor + sublabel.backgroundColor = super.backgroundColor ?? UIColor.clear + sublabel.shadowColor = super.shadowColor + sublabel.shadowOffset = super.shadowOffset + for prop in properties { + let value = super.value(forKey: prop) + sublabel.setValue(value, forKeyPath: prop) + } + } + + // + // MARK: - MarqueeLabel Heavy Lifting + // + + override open func layoutSubviews() { + super.layoutSubviews() + + updateAndScroll() + } + + override open func willMove(toWindow newWindow: UIWindow?) { + if newWindow == nil { + shutdownLabel() + } + } + + override open func didMoveToWindow() { + if self.window == nil { + shutdownLabel() + } else { + updateAndScroll() + } + } + + private func updateAndScroll() { + // Do not automatically begin scroll if tapToScroll is true + updateAndScroll(overrideHold: false) + } + + private func updateAndScroll(overrideHold: Bool) { + // Check if scrolling can occur + if !labelReadyForScroll() { + return + } + + // Calculate expected size + let expectedLabelSize = sublabelSize() + + // Invalidate intrinsic size + invalidateIntrinsicContentSize() + + // Move label to home + returnLabelToHome() + + // Check if label should scroll + // Note that the holdScrolling propery does not affect this + if !labelShouldScroll() { + // Set text alignment and break mode to act like a normal label + sublabel.textAlignment = super.textAlignment + sublabel.lineBreakMode = super.lineBreakMode + + let labelFrame: CGRect + switch type { + case .continuousReverse, .rightLeft: + labelFrame = bounds.divided(atDistance: leadingBuffer, from: CGRectEdge.maxXEdge).remainder.integral + default: + labelFrame = CGRect(x: leadingBuffer, y: 0.0, width: bounds.size.width - leadingBuffer, height: bounds.size.height).integral + } + + homeLabelFrame = labelFrame + awayOffset = 0.0 + + // Remove an additional sublabels (for continuous types) + repliLayer?.instanceCount = 1 + + // Set the sublabel frame to calculated labelFrame + sublabel.frame = labelFrame + + // Remove fade, as by definition none is needed in this case + removeGradientMask() + + return + } + + // Label DOES need to scroll + + // Spacing between primary and second sublabel must be at least equal to leadingBuffer, and at least equal to the fadeLength + let minTrailing = max(max(leadingBuffer, trailingBuffer), fadeLength) + + // Determine positions and generate scroll steps + let sequence: [MarqueeStep] + + switch type { + case .continuous, .continuousReverse: + if type == .continuous { + homeLabelFrame = CGRect(x: leadingBuffer, y: 0.0, width: expectedLabelSize.width, height: bounds.size.height).integral + awayOffset = -(homeLabelFrame.size.width + minTrailing) + } else { // .ContinuousReverse + homeLabelFrame = CGRect(x: bounds.size.width - (expectedLabelSize.width + leadingBuffer), y: 0.0, width: expectedLabelSize.width, height: bounds.size.height).integral + awayOffset = (homeLabelFrame.size.width + minTrailing) + } + + // Find when the lead label will be totally offscreen + let offsetDistance = awayOffset + let offscreenAmount = homeLabelFrame.size.width + let startFadeFraction = abs(offscreenAmount / offsetDistance) + // Find when the animation will hit that point + let startFadeTimeFraction = timingFunctionForAnimationCurve(animationCurve).durationPercentageForPositionPercentage(startFadeFraction, duration: (animationDelay + animationDuration)) + let startFadeTime = startFadeTimeFraction * animationDuration + + sequence = scrollSequence ?? [ + ScrollStep(timeStep: 0.0, position: .home, edgeFades: .trailing), // Starting point, at home, with trailing fade + ScrollStep(timeStep: animationDelay, position: .home, edgeFades: .trailing), // Delay at home, maintaining fade state + FadeStep(timeStep: 0.2, edgeFades: [.leading, .trailing]), // 0.2 sec after scroll start, fade leading edge in as well + FadeStep(timeStep: (startFadeTime - animationDuration), // Maintain fade state until just before reaching end of scroll animation + edgeFades: [.leading, .trailing]), + ScrollStep(timeStep: animationDuration, timingFunction: animationCurve, // Ending point (back at home), with animationCurve transition, with trailing fade + position: .away, edgeFades: .trailing) + ] + + // Set frame and text + sublabel.frame = homeLabelFrame + + // Configure replication + repliLayer?.instanceCount = 2 + repliLayer?.instanceTransform = CATransform3DMakeTranslation(-awayOffset, 0.0, 0.0) + + case .leftRight, .left, .rightLeft, .right: + if type == .leftRight || type == .left { + homeLabelFrame = CGRect(x: leadingBuffer, y: 0.0, width: expectedLabelSize.width, height: bounds.size.height).integral + awayOffset = bounds.size.width - (expectedLabelSize.width + leadingBuffer + trailingBuffer) + // Enforce text alignment for this type + sublabel.textAlignment = NSTextAlignment.left + } else { + homeLabelFrame = CGRect(x: bounds.size.width - (expectedLabelSize.width + leadingBuffer), y: 0.0, width: expectedLabelSize.width, height: bounds.size.height).integral + awayOffset = (expectedLabelSize.width + trailingBuffer + leadingBuffer) - bounds.size.width + // Enforce text alignment for this type + sublabel.textAlignment = NSTextAlignment.right + } + // Set frame and text + sublabel.frame = homeLabelFrame + + // Remove any replication + repliLayer?.instanceCount = 1 + + if type == .leftRight || type == .rightLeft { + sequence = scrollSequence ?? [ + ScrollStep(timeStep: 0.0, position: .home, edgeFades: .trailing), // Starting point, at home, with trailing fade + ScrollStep(timeStep: animationDelay, position: .home, edgeFades: .trailing), // Delay at home, maintaining fade state + FadeStep(timeStep: 0.2, edgeFades: [.leading, .trailing]), // 0.2 sec after delay ends, fade leading edge in as well + FadeStep(timeStep: -0.2, edgeFades: [.leading, .trailing]), // Maintain fade state until 0.2 sec before reaching away position + ScrollStep(timeStep: animationDuration, timingFunction: animationCurve, // Away position, using animationCurve transition, with only leading edge faded in + position: .away, edgeFades: .leading), + ScrollStep(timeStep: animationDelay, position: .away, edgeFades: .leading), // Delay at away, maintaining fade state (leading only) + FadeStep(timeStep: 0.2, edgeFades: [.leading, .trailing]), // 0.2 sec after delay ends, fade trailing edge back in as well + FadeStep(timeStep: -0.2, edgeFades: [.leading, .trailing]), // Maintain fade state until 0.2 sec before reaching home position + ScrollStep(timeStep: animationDuration, timingFunction: animationCurve, // Ending point, back at home, with only trailing fade + position: .home, edgeFades: .trailing) + ] + } else { // .left or .right + sequence = scrollSequence ?? [ + ScrollStep(timeStep: 0.0, position: .home, edgeFades: .trailing), // Starting point, at home, with trailing fade + ScrollStep(timeStep: animationDelay, position: .home, edgeFades: .trailing), // Delay at home, maintaining fade state + FadeStep(timeStep: 0.2, edgeFades: [.leading, .trailing]), // 0.2 sec after delay ends, fade leading edge in as well + FadeStep(timeStep: -0.2, edgeFades: [.leading, .trailing]), // Maintain fade state until 0.2 sec before reaching away position + ScrollStep(timeStep: animationDuration, timingFunction: animationCurve, // Away position, using animationCurve transition, with only leading edge faded in + position: .away, edgeFades: .leading), + ScrollStep(timeStep: animationDelay, position: .away, edgeFades: .leading), // "Delay" at away, maintaining fade state + ] + } + } + + + + // Configure gradient for current condition + applyGradientMask(fadeLength, animated: !self.labelize) + + if overrideHold || (!holdScrolling && !overrideHold) { + beginScroll(sequence) + } + } + + private func sublabelSize() -> CGSize { + // Bound the expected size + let maximumLabelSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) + // Calculate the expected size + var expectedLabelSize = sublabel.sizeThatFits(maximumLabelSize) + + #if os(tvOS) + // Sanitize width to 16384.0 (largest width a UILabel will draw on tvOS) + expectedLabelSize.width = min(expectedLabelSize.width, 16384.0) + #else + // Sanitize width to 5461.0 (largest width a UILabel will draw on an iPhone 6S Plus) + expectedLabelSize.width = min(expectedLabelSize.width, 5461.0) + #endif + + // Adjust to own height (make text baseline match normal label) + expectedLabelSize.height = bounds.size.height + return expectedLabelSize + } + + override open func sizeThatFits(_ size: CGSize) -> CGSize { + var fitSize = sublabel.sizeThatFits(size) + fitSize.width += leadingBuffer + return fitSize + } + + // + // MARK: - Animation Handling + // + + open func labelShouldScroll() -> Bool { + // Check for nil string + if sublabel.text == nil { + return false + } + + // Check for empty string + if sublabel.text!.isEmpty { + return false + } + + // Check if the label string fits + let labelTooLarge = (sublabelSize().width + leadingBuffer) > self.bounds.size.width + CGFloat.ulpOfOne + let animationHasDuration = speed.value > 0.0 + return (!labelize && labelTooLarge && animationHasDuration) + } + + private func labelReadyForScroll() -> Bool { + // Check if we have a superview + if superview == nil { + return false + } + + // Check if we are attached to a window + if window == nil { + return false + } + + // Check if our view controller is ready + let viewController = firstAvailableViewController() + if viewController != nil { + if !viewController!.isViewLoaded { + return false + } + } + + return true + } + + private func returnLabelToHome() { + // Remove any gradient animation + maskLayer?.removeAllAnimations() + + // Remove all sublabel position animations + sublabel.layer.removeAllAnimations() + + // Remove completion block + scrollCompletionBlock = nil + } + + private func beginScroll(_ sequence: [MarqueeStep]) { + let scroller = generateScrollAnimation(sequence) + let fader = generateGradientAnimation(sequence, totalDuration: scroller.duration) + + scroll(scroller, fader: fader) + } + + private func scroll(_ scroller: MLAnimation, fader: MLAnimation?) { + // Check for conditions which would prevent scrolling + if !labelReadyForScroll() { + return + } + // Convert fader to var + var fader = fader + + // Call pre-animation hook + labelWillBeginScroll() + + // Start animation transactions + CATransaction.begin() + CATransaction.setAnimationDuration(TimeInterval(scroller.duration)) + + // Create gradient animation, if needed + let gradientAnimation: CAKeyframeAnimation? + // Check for IBDesignable + #if !TARGET_INTERFACE_BUILDER + if fadeLength > 0.0 { + // Remove any setup animation, but apply final values + if let setupAnim = maskLayer?.animation(forKey: "setupFade") as? CABasicAnimation, let finalColors = setupAnim.toValue as? [CGColor] { + maskLayer?.colors = finalColors + } + maskLayer?.removeAnimation(forKey: "setupFade") + + // Generate animation if needed + if let previousAnimation = fader?.anim { + gradientAnimation = previousAnimation + } else { + gradientAnimation = nil + } + + // Apply fade animation + maskLayer?.add(gradientAnimation!, forKey: "gradient") + } else { + // No animation needed + fader = nil + } + #else + fader = nil + #endif + + scrollCompletionBlock = { [weak self] (finished: Bool) in + guard self != nil else { + return + } + + // Call returned home function + self!.labelReturnedToHome(finished) + + // Check to ensure that: + + // 1) The instance is still attached to a window - this completion block is called for + // many reasons, including if the animation is removed due to the view being removed + // from the UIWindow (typically when the view controller is no longer the "top" view) + guard self!.window != nil else { + return + } + // 2) We don't double fire if an animation already exists + guard self!.sublabel.layer.animation(forKey: "position") == nil else { + return + } + // 3) We don't not start automatically if the animation was unexpectedly interrupted + guard finished else { + // Do not continue into the next loop + return + } + // 4) A completion block still exists for the NEXT loop. A notable case here is if + // returnLabelToHome() was called during a subclass's labelReturnToHome() function + guard self!.scrollCompletionBlock != nil else { + return + } + + // Begin again, if conditions met + if self!.labelShouldScroll() && !self!.tapToScroll && !self!.holdScrolling { + // Perform completion callback + self!.scroll(scroller, fader: fader) + } + } + + // Perform scroll animation + scroller.anim.setValue(true, forKey: MarqueeKeys.CompletionClosure.rawValue) + scroller.anim.delegate = self + if type == .left || type == .right { + // Make it stay at away permanently + scroller.anim.isRemovedOnCompletion = false + scroller.anim.fillMode = .forwards + } + sublabel.layer.add(scroller.anim, forKey: "position") + + CATransaction.commit() + } + + private func generateScrollAnimation(_ sequence: [MarqueeStep]) -> MLAnimation { + // Create scroller, which defines the animation to perform + let homeOrigin = homeLabelFrame.origin + let awayOrigin = offsetCGPoint(homeLabelFrame.origin, offset: awayOffset) + + let scrollSteps = sequence.filter({ $0 is ScrollStep }) as! [ScrollStep] + let totalDuration = scrollSteps.reduce(0.0) { $0 + $1.timeStep } + + // Build scroll data + var totalTime: CGFloat = 0.0 + var scrollKeyTimes = [NSNumber]() + var scrollKeyValues = [NSValue]() + var scrollTimingFunctions = [CAMediaTimingFunction]() + + for (offset, step) in scrollSteps.enumerated() { + // Scroll Times + totalTime += step.timeStep + scrollKeyTimes.append(NSNumber(value:Float(totalTime/totalDuration))) + + // Scroll Values + let scrollPosition: CGPoint + switch step.position { + case .home: + scrollPosition = homeOrigin + case .away: + scrollPosition = awayOrigin + case .partial(let frac): + scrollPosition = offsetCGPoint(homeOrigin, offset: awayOffset*frac) + } + scrollKeyValues.append(NSValue(cgPoint:scrollPosition)) + + // Scroll Timing Functions + // Only need n-1 timing functions, so discard the first value as it's unused + if offset == 0 { continue } + scrollTimingFunctions.append(timingFunctionForAnimationCurve(step.timingFunction)) + } + + // Create animation + let animation = CAKeyframeAnimation(keyPath: "position") + // Set values + animation.keyTimes = scrollKeyTimes + animation.values = scrollKeyValues + animation.timingFunctions = scrollTimingFunctions + + return (anim: animation, duration: totalDuration) + } + + private func generateGradientAnimation(_ sequence: [MarqueeStep], totalDuration: CGFloat) -> MLAnimation { + // Setup + var totalTime: CGFloat = 0.0 + var stepTime: CGFloat = 0.0 + var fadeKeyValues = [[CGColor]]() + var fadeKeyTimes = [NSNumber]() + var fadeTimingFunctions = [CAMediaTimingFunction]() + let transp = UIColor.clear.cgColor + let opaque = UIColor.black.cgColor + + // Filter to get only scroll steps and valid precedent/subsequent fade steps + let fadeSteps = sequence.enumerated().filter { (arg: (offset: Int, element: MarqueeStep)) -> Bool in + let (offset, element) = arg + + // Include all Scroll Steps + if element is ScrollStep { return true } + + // Include all Fade Steps that have a directly preceding or subsequent Scroll Step + // Exception: Fade Step cannot be first step + if offset == 0 { return false } + + // Subsequent step if 1) positive/zero time step and 2) follows a Scroll Step + let subsequent = element.timeStep >= 0 && (sequence[max(0, offset - 1)] is ScrollStep) + // Precedent step if 1) negative time step and 2) precedes a Scroll Step + let precedent = element.timeStep < 0 && (sequence[min(sequence.count - 1, offset + 1)] is ScrollStep) + + return (precedent || subsequent) + } + + for (offset, step) in fadeSteps { + // Fade times + if step is ScrollStep { + totalTime += step.timeStep + stepTime = totalTime + } else { + if step.timeStep >= 0 { + // Is a Subsequent + stepTime = totalTime + step.timeStep + } else { + // Is a Precedent, grab next step + stepTime = totalTime + fadeSteps[offset + 1].element.timeStep + step.timeStep + } + } + fadeKeyTimes.append(NSNumber(value:Float(stepTime/totalDuration))) + + // Fade Values + let values: [CGColor] + let leading = step.edgeFades.contains(.leading) ? transp : opaque + let trailing = step.edgeFades.contains(.trailing) ? transp : opaque + switch type { + case .leftRight, .left, .continuous: + values = [leading, opaque, opaque, trailing] + case .rightLeft, .right, .continuousReverse: + values = [trailing, opaque, opaque, leading] + } + fadeKeyValues.append(values) + + // Fade Timing Function + // Only need n-1 timing functions, so discard the first value as it's unused + if offset == 0 { continue } + fadeTimingFunctions.append(timingFunctionForAnimationCurve(step.timingFunction)) + } + + // Create new animation + let animation = CAKeyframeAnimation(keyPath: "colors") + + animation.values = fadeKeyValues + animation.keyTimes = fadeKeyTimes + animation.timingFunctions = fadeTimingFunctions + + return (anim: animation, duration: max(totalTime, totalDuration)) + } + + private func applyGradientMask(_ fadeLength: CGFloat, animated: Bool, firstStep: MarqueeStep? = nil) { + // Remove any in-flight animations + maskLayer?.removeAllAnimations() + + // Check for zero-length fade + if fadeLength <= 0.0 { + removeGradientMask() + return + } + + // Configure gradient mask without implicit animations + CATransaction.begin() + CATransaction.setDisableActions(true) + + // Determine if gradient mask needs to be created + let gradientMask: CAGradientLayer + if let currentMask = self.maskLayer { + // Mask layer already configured + gradientMask = currentMask + } else { + // No mask exists, create new mask + gradientMask = CAGradientLayer() + gradientMask.shouldRasterize = true + gradientMask.rasterizationScale = UIScreen.main.scale + gradientMask.startPoint = CGPoint(x:0.0, y:0.5) + gradientMask.endPoint = CGPoint(x:1.0, y:0.5) + } + + // Check if there is a mask to layer size mismatch + if gradientMask.bounds != self.layer.bounds { + // Adjust stops based on fade length + let leftFadeStop = fadeLength/self.bounds.size.width + let rightFadeStop = 1.0 - fadeLength/self.bounds.size.width + gradientMask.locations = [0.0, leftFadeStop, rightFadeStop, 1.0].map { NSNumber(value: Float($0)) } + } + + gradientMask.bounds = self.layer.bounds + gradientMask.position = CGPoint(x:self.bounds.midX, y:self.bounds.midY) + + // Set up colors + let transparent = UIColor.clear.cgColor + let opaque = UIColor.black.cgColor + + // Set mask + self.layer.mask = gradientMask + + // Determine colors for non-scrolling label (i.e. at home) + let adjustedColors: [CGColor] + let trailingFadeNeeded = self.labelShouldScroll() + + switch type { + case .continuousReverse, .rightLeft: + adjustedColors = [(trailingFadeNeeded ? transparent : opaque), opaque, opaque, opaque] + + // .Continuous, .LeftRight + default: + adjustedColors = [opaque, opaque, opaque, (trailingFadeNeeded ? transparent : opaque)] + } + + // Check for IBDesignable + #if TARGET_INTERFACE_BUILDER + gradientMask.colors = adjustedColors + CATransaction.commit() + #else + if animated { + // Finish transaction + CATransaction.commit() + + // Create animation for color change + let colorAnimation = GradientSetupAnimation(keyPath: "colors") + colorAnimation.fromValue = gradientMask.colors + colorAnimation.toValue = adjustedColors + colorAnimation.fillMode = .forwards + colorAnimation.isRemovedOnCompletion = false + colorAnimation.delegate = self + gradientMask.add(colorAnimation, forKey: "setupFade") + } else { + gradientMask.colors = adjustedColors + CATransaction.commit() + } + #endif + } + + private func removeGradientMask() { + self.layer.mask = nil + } + + private func timingFunctionForAnimationCurve(_ curve: UIView.AnimationCurve) -> CAMediaTimingFunction { + let timingFunction: CAMediaTimingFunctionName? + + switch curve { + case .easeIn: + timingFunction = .easeIn + case .easeInOut: + timingFunction = .easeInEaseOut + case .easeOut: + timingFunction = .easeOut + default: + timingFunction = .linear + } + + return CAMediaTimingFunction(name: timingFunction!) + } + + private func transactionDurationType(_ labelType: MarqueeType, interval: CGFloat, delay: CGFloat) -> TimeInterval { + switch labelType { + case .leftRight, .rightLeft: + return TimeInterval(2.0 * (delay + interval)) + default: + return TimeInterval(delay + interval) + } + } + + public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { + if let setupAnim = anim as? GradientSetupAnimation { + if let finalColors = setupAnim.toValue as? [CGColor] { + maskLayer?.colors = finalColors + } + // Remove regardless, since we set removeOnCompletion = false + maskLayer?.removeAnimation(forKey: "setupFade") + } else { + scrollCompletionBlock?(flag) + } + } + + + // + // MARK: - Private details + // + + private var sublabel = UILabel() + + fileprivate var homeLabelFrame = CGRect.zero + fileprivate var awayOffset: CGFloat = 0.0 + + override open class var layerClass: AnyClass { + return CAReplicatorLayer.self + } + + fileprivate weak var repliLayer: CAReplicatorLayer? { + return self.layer as? CAReplicatorLayer + } + + fileprivate weak var maskLayer: CAGradientLayer? { + return self.layer.mask as! CAGradientLayer? + } + + fileprivate var scrollCompletionBlock: MLAnimationCompletionBlock? + + override open func draw(_ layer: CALayer, in ctx: CGContext) { + // Do NOT call super, to prevent UILabel superclass from drawing into context + // Label drawing is handled by sublabel and CAReplicatorLayer layer class + + // Draw only background color + if let bgColor = backgroundColor { + ctx.setFillColor(bgColor.cgColor) + ctx.fill(layer.bounds) + } + } + + fileprivate enum MarqueeKeys: String { + case Restart = "MLViewControllerRestart" + case Labelize = "MLShouldLabelize" + case Animate = "MLShouldAnimate" + case CompletionClosure = "MLAnimationCompletion" + } + + class fileprivate func notifyController(_ controller: UIViewController, message: MarqueeKeys) { + NotificationCenter.default.post(name: Notification.Name(rawValue: message.rawValue), object: nil, userInfo: ["controller" : controller]) + } + + @objc public func restartForViewController(_ notification: Notification) { + if let controller = (notification as NSNotification).userInfo?["controller"] as? UIViewController { + if controller === self.firstAvailableViewController() { + self.restartLabel() + } + } + } + + @objc public func labelizeForController(_ notification: Notification) { + if let controller = (notification as NSNotification).userInfo?["controller"] as? UIViewController { + if controller === self.firstAvailableViewController() { + self.labelize = true + } + } + } + + @objc public func animateForController(_ notification: Notification) { + if let controller = (notification as NSNotification).userInfo?["controller"] as? UIViewController { + if controller === self.firstAvailableViewController() { + self.labelize = false + } + } + } + + + // + // MARK: - Label Control + // + + /** + Overrides any non-size condition which is preventing the receiver from automatically scrolling, and begins a scroll animation. + + Currently the only non-size conditions which can prevent a label from scrolling are the `tapToScroll` and `holdScrolling` properties. This + method will not force a label with a string that fits inside the label bounds (i.e. that would not automatically scroll) to begin a scroll + animation. + + Upon the completion of the first forced scroll animation, the receiver will not automatically continue to scroll unless the conditions + preventing scrolling have been removed. + + - Note: This method has no effect if called during an already in-flight scroll animation. + + - SeeAlso: restartLabel + */ + public func triggerScrollStart() { + if labelShouldScroll() && !awayFromHome { + updateAndScroll() + } + } + + /** + Immediately resets the label to the home position, cancelling any in-flight scroll animation, and restarts the scroll animation if the appropriate conditions are met. + + - SeeAlso: resetLabel + - SeeAlso: triggerScrollStart + */ + @objc public func restartLabel() { + // Shutdown the label + shutdownLabel() + // Restart scrolling if appropriate + if labelShouldScroll() && !tapToScroll && !holdScrolling { + updateAndScroll() + } + } + + /** + Resets the label text, recalculating the scroll animation. + + The text is immediately returned to the home position, and the scroll animation positions are cleared. Scrolling will not resume automatically after + a call to this method. To re-initiate scrolling, use either a call to `restartLabel` or make a change to a UILabel property such as text, bounds/frame, + font, font size, etc. + + - SeeAlso: restartLabel + */ + @available(*, deprecated, message : "Use the shutdownLabel function instead") + public func resetLabel() { + returnLabelToHome() + homeLabelFrame = CGRect.null + awayOffset = 0.0 + } + + /** + Immediately resets the label to the home position, cancelling any in-flight scroll animation. + + The text is immediately returned to the home position. Scrolling will not resume automatically after a call to this method. + To re-initiate scrolling use a call to `restartLabel` or `triggerScrollStart`, or make a change to a UILabel property such as text, bounds/frame, + font, font size, etc. + + - SeeAlso: restartLabel + - SeeAlso: triggerScrollStart + */ + @objc public func shutdownLabel() { + // Bring label to home location + returnLabelToHome() + // Apply gradient mask for home location + applyGradientMask(fadeLength, animated: false) + } + + /** + Pauses the text scrolling animation, at any point during an in-progress animation. + + - Note: This method has no effect if a scroll animation is NOT already in progress. To prevent automatic scrolling on a newly-initialized label prior to its presentation onscreen, see the `holdScrolling` property. + + - SeeAlso: holdScrolling + - SeeAlso: unpauseLabel + */ + public func pauseLabel() { + // Prevent pausing label while not in scrolling animation, or when already paused + guard !isPaused && awayFromHome else { + return + } + + // Pause sublabel position animations + let labelPauseTime = sublabel.layer.convertTime(CACurrentMediaTime(), from: nil) + sublabel.layer.speed = 0.0 + sublabel.layer.timeOffset = labelPauseTime + + // Pause gradient fade animation + let gradientPauseTime = maskLayer?.convertTime(CACurrentMediaTime(), from:nil) + maskLayer?.speed = 0.0 + maskLayer?.timeOffset = gradientPauseTime! + } + + /** + Un-pauses a previously paused text scrolling animation. This method has no effect if the label was not previously paused using `pauseLabel`. + + - SeeAlso: pauseLabel + */ + public func unpauseLabel() { + // Only unpause if label was previously paused + guard isPaused else { + return + } + + // Unpause sublabel position animations + let labelPausedTime = sublabel.layer.timeOffset + sublabel.layer.speed = 1.0 + sublabel.layer.timeOffset = 0.0 + sublabel.layer.beginTime = 0.0 + sublabel.layer.beginTime = sublabel.layer.convertTime(CACurrentMediaTime(), from:nil) - labelPausedTime + + // Unpause gradient fade animation + let gradientPauseTime = maskLayer?.timeOffset + maskLayer?.speed = 1.0 + maskLayer?.timeOffset = 0.0 + maskLayer?.beginTime = 0.0 + maskLayer?.beginTime = maskLayer!.convertTime(CACurrentMediaTime(), from:nil) - gradientPauseTime! + } + + @objc public func labelWasTapped(_ recognizer: UIGestureRecognizer) { + if labelShouldScroll() && !awayFromHome { + // Set shouldBeginScroll to true to begin single scroll due to tap + updateAndScroll(overrideHold: true) + } + } + + /** + Called when the label animation is about to begin. + + The default implementation of this method does nothing. Subclasses may override this method in order to perform any custom actions just as + the label animation begins. This is only called in the event that the conditions for scrolling to begin are met. + */ + open func labelWillBeginScroll() { + // Default implementation does nothing - override to customize + return + } + + /** + Called when the label animation has finished, and the label is at the home position. + + The default implementation of this method does nothing. Subclasses may override this method in order to perform any custom actions jas as + the label animation completes, and before the next animation would begin (assuming the scroll conditions are met). + + - Parameter finished: A Boolean that indicates whether or not the scroll animation actually finished before the completion handler was called. + + - Warning: This method will be called, and the `finished` parameter will be `NO`, when any property changes are made that would cause the label + scrolling to be automatically reset. This includes changes to label text and font/font size changes. + */ + open func labelReturnedToHome(_ finished: Bool) { + // Default implementation does nothing - override to customize + return + } + + // + // MARK: - Modified UILabel Functions/Getters/Setters + // + + #if os(iOS) + override open func forBaselineLayout() -> UIView { + // Use subLabel view for handling baseline layouts + return sublabel + } + + override open var forLastBaselineLayout: UIView { + // Use subLabel view for handling baseline layouts + return sublabel + } + #endif + + override open var text: String? { + get { + return sublabel.text + } + + set { + if sublabel.text == newValue { + return + } + sublabel.text = newValue + updateAndScroll() + super.text = text + } + } + + override open var attributedText: NSAttributedString? { + get { + return sublabel.attributedText + } + + set { + if sublabel.attributedText == newValue { + return + } + sublabel.attributedText = newValue + updateAndScroll() + super.attributedText = attributedText + } + } + + override open var font: UIFont! { + get { + return sublabel.font + } + + set { + if sublabel.font == newValue { + return + } + sublabel.font = newValue + super.font = newValue + + updateAndScroll() + } + } + + override open var textColor: UIColor! { + get { + return sublabel.textColor + } + + set { + sublabel.textColor = newValue + super.textColor = newValue + } + } + + override open var backgroundColor: UIColor? { + get { + return sublabel.backgroundColor + } + + set { + sublabel.backgroundColor = newValue + super.backgroundColor = newValue + } + } + + override open var shadowColor: UIColor? { + get { + return sublabel.shadowColor + } + + set { + sublabel.shadowColor = newValue + super.shadowColor = newValue + } + } + + override open var shadowOffset: CGSize { + get { + return sublabel.shadowOffset + } + + set { + sublabel.shadowOffset = newValue + super.shadowOffset = newValue + } + } + + override open var highlightedTextColor: UIColor? { + get { + return sublabel.highlightedTextColor + } + + set { + sublabel.highlightedTextColor = newValue + super.highlightedTextColor = newValue + } + } + + override open var isHighlighted: Bool { + get { + return sublabel.isHighlighted + } + + set { + sublabel.isHighlighted = newValue + super.isHighlighted = newValue + } + } + + override open var isEnabled: Bool { + get { + return sublabel.isEnabled + } + + set { + sublabel.isEnabled = newValue + super.isEnabled = newValue + } + } + + override open var numberOfLines: Int { + get { + return super.numberOfLines + } + + set { + // By the nature of MarqueeLabel, this is 1 + super.numberOfLines = 1 + } + } + + override open var adjustsFontSizeToFitWidth: Bool { + get { + return super.adjustsFontSizeToFitWidth + } + + set { + // By the nature of MarqueeLabel, this is false + super.adjustsFontSizeToFitWidth = false + } + } + + override open var minimumScaleFactor: CGFloat { + get { + return super.minimumScaleFactor + } + + set { + super.minimumScaleFactor = 0.0 + } + } + + override open var baselineAdjustment: UIBaselineAdjustment { + get { + return sublabel.baselineAdjustment + } + + set { + sublabel.baselineAdjustment = newValue + super.baselineAdjustment = newValue + } + } + + override open var intrinsicContentSize: CGSize { + var content = sublabel.intrinsicContentSize + content.width += leadingBuffer + return content + } + + override open var tintColor: UIColor! { + get { + return sublabel.tintColor + } + + set { + sublabel.tintColor = newValue + super.tintColor = newValue + } + } + + override open func tintColorDidChange() { + super.tintColorDidChange() + sublabel.tintColorDidChange() + } + + override open var contentMode: UIView.ContentMode { + get { + return sublabel.contentMode + } + + set { + super.contentMode = contentMode + sublabel.contentMode = newValue + } + } + + open override var isAccessibilityElement: Bool { + didSet { + sublabel.isAccessibilityElement = self.isAccessibilityElement + } + } + + // + // MARK: - Support + // + + fileprivate func offsetCGPoint(_ point: CGPoint, offset: CGFloat) -> CGPoint { + return CGPoint(x: point.x + offset, y: point.y) + } + + // + // MARK: - Deinit + // + + deinit { + NotificationCenter.default.removeObserver(self) + } + +} + + +// +// MARK: - Support +// +public protocol MarqueeStep { + var timeStep: CGFloat { get } + var timingFunction: UIView.AnimationCurve { get } + var edgeFades: EdgeFade { get } +} + + +/** + `ScrollStep` types define the label position at a specified time delta since the last `ScrollStep` step, as well as + the animation curve to that position and edge fade state at the position + */ +public struct ScrollStep: MarqueeStep { + /** + An enum that provides the possible positions defined by a ScrollStep + - `home`: The starting, default position of the label + - `away`: The calculated position that results in the entirety of the label scrolling past. + - `partial(CGFloat)`: A fractional value, specified by the associated CGFloat value, between the `home` and `away` positions (must be between 0.0 and 1.0). + + The `away` position depends on the MarqueeLabel `type` value. + - For `left`, `leftRight`, `right`, and `rightLeft` types, the `away` position means the trailing edge of the label + is visible. For `leftRight` and `rightLeft` default types, the scroll animation reverses direction after reaching + this point and returns to the `home` position. + - For `continuous` and `continuousReverse` types, the `away` position is the location such that if the scroll is completed + at this point (i.e. the animation is removed), there will be no visible change in the label appearance. + */ + public enum Position { + case home + case away + case partial(CGFloat) + } + + /** + The desired time between this step and the previous `ScrollStep` in a sequence. + */ + public let timeStep: CGFloat + + /** + The animation curve to utilize between the previous `ScrollStep` in a sequence and this step. + + - Note: The animation curve value for the first `ScrollStep` in a sequence has no effect. + */ + public let timingFunction: UIView.AnimationCurve + + /** + The position of the label for this scroll step. + - SeeAlso: Position + */ + public let position: Position + + /** + The option set defining the edge fade state for this scroll step. + + Possible options include `.leading` and `.trailing`, corresponding to the leading edge of the label scrolling (i.e. + the direction of scroll) and trailing edge of the label. + */ + public let edgeFades: EdgeFade + + public init(timeStep: CGFloat, timingFunction: UIView.AnimationCurve = .linear, position: Position, edgeFades: EdgeFade) { + self.timeStep = timeStep + self.position = position + self.edgeFades = edgeFades + self.timingFunction = timingFunction + } +} + + +/** + `FadeStep` types allow additional edge fade state definitions, around the states defined by the `ScrollStep` steps of + a sequence. `FadeStep` steps are defined by the time delta to the preceding or subsequent `ScrollStep` step and the timing + function to their edge fade state. + + - Note: A `FadeStep` cannot be the first step in a sequence. A `FadeStep` defined as such will be ignored. + */ +public struct FadeStep: MarqueeStep { + /** + The desired time between this `FadeStep` and the preceding or subsequent `ScrollStep` in a sequence. + + `FadeSteps` with a negative `timeStep` value will be associated _only_ with an immediately-subsequent `ScrollStep` step + in the sequence. + + `FadeSteps` with a positive `timeStep` value will be associated _only_ with an immediately-prior `ScrollStep` step in the + sequence. + + - Note: A `FadeStep` with a `timeStep` value of 0.0 will have no effect, and is the same as defining the fade state with + a `ScrollStep`. + */ + public let timeStep: CGFloat + + /** + The animation curve to utilize between the previous fade state in a sequence and this step. + */ + public let timingFunction: UIView.AnimationCurve + + /** + The option set defining the edge fade state for this fade step. + + Possible options include `.leading` and `.trailing`, corresponding to the leading edge of the label scrolling (i.e. + the direction of scroll) and trailing edge of the label. + + As an Option Set type, both edge fade states may be defined using an array literal: `[.leading, .trailing]`. + */ + public let edgeFades: EdgeFade + + public init(timeStep: CGFloat, timingFunction: UIView.AnimationCurve = .linear, edgeFades: EdgeFade) { + self.timeStep = timeStep + self.timingFunction = timingFunction + self.edgeFades = edgeFades + } +} + +public struct EdgeFade: OptionSet { + public let rawValue: Int + public static let leading = EdgeFade(rawValue: 1 << 0) + public static let trailing = EdgeFade(rawValue: 1 << 1) + + public init(rawValue: Int) { + self.rawValue = rawValue + } +} + +// Define helpful typealiases +fileprivate typealias MLAnimationCompletionBlock = (_ finished: Bool) -> Void +fileprivate typealias MLAnimation = (anim: CAKeyframeAnimation, duration: CGFloat) + +fileprivate class GradientSetupAnimation: CABasicAnimation { +} + +fileprivate extension UIResponder { + // Thanks to Phil M + // http://stackoverflow.com/questions/1340434/get-to-uiviewcontroller-from-uiview-on-iphone + + func firstAvailableViewController() -> UIViewController? { + // convenience function for casting and to "mask" the recursive function + return self.traverseResponderChainForFirstViewController() + } + + func traverseResponderChainForFirstViewController() -> UIViewController? { + if let nextResponder = self.next { + if nextResponder is UIViewController { + return nextResponder as? UIViewController + } else if nextResponder is UIView { + return nextResponder.traverseResponderChainForFirstViewController() + } else { + return nil + } + } + return nil + } +} + +fileprivate extension CAMediaTimingFunction { + + func durationPercentageForPositionPercentage(_ positionPercentage: CGFloat, duration: CGFloat) -> CGFloat { + // Finds the animation duration percentage that corresponds with the given animation "position" percentage. + // Utilizes Newton's Method to solve for the parametric Bezier curve that is used by CAMediaAnimation. + + let controlPoints = self.controlPoints() + let epsilon: CGFloat = 1.0 / (100.0 * CGFloat(duration)) + + // Find the t value that gives the position percentage we want + let t_found = solveTforY(positionPercentage, epsilon: epsilon, controlPoints: controlPoints) + + // With that t, find the corresponding animation percentage + let durationPercentage = XforCurveAt(t_found, controlPoints: controlPoints) + + return durationPercentage + } + + func solveTforY(_ y_0: CGFloat, epsilon: CGFloat, controlPoints: [CGPoint]) -> CGFloat { + // Use Newton's Method: http://en.wikipedia.org/wiki/Newton's_method + // For first guess, use t = y (i.e. if curve were linear) + var t0 = y_0 + var t1 = y_0 + var f0, df0: CGFloat + + for _ in 0..<15 { + // Base this iteration of t1 calculated from last iteration + t0 = t1 + // Calculate f(t0) + f0 = YforCurveAt(t0, controlPoints:controlPoints) - y_0 + // Check if this is close (enough) + if abs(f0) < epsilon { + // Done! + return t0 + } + // Else continue Newton's Method + df0 = derivativeCurveYValueAt(t0, controlPoints:controlPoints) + // Check if derivative is small or zero ( http://en.wikipedia.org/wiki/Newton's_method#Failure_analysis ) + if abs(df0) < 1e-6 { + break + } + // Else recalculate t1 + t1 = t0 - f0/df0 + } + + // Give up - shouldn't ever get here...I hope + print("MarqueeLabel: Failed to find t for Y input!") + return t0 + } + + func YforCurveAt(_ t: CGFloat, controlPoints: [CGPoint]) -> CGFloat { + let P0 = controlPoints[0] + let P1 = controlPoints[1] + let P2 = controlPoints[2] + let P3 = controlPoints[3] + + // Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves + let y0 = (pow((1.0 - t), 3.0) * P0.y) + let y1 = (3.0 * pow(1.0 - t, 2.0) * t * P1.y) + let y2 = (3.0 * (1.0 - t) * pow(t, 2.0) * P2.y) + let y3 = (pow(t, 3.0) * P3.y) + + return y0 + y1 + y2 + y3 + } + + func XforCurveAt(_ t: CGFloat, controlPoints: [CGPoint]) -> CGFloat { + let P0 = controlPoints[0] + let P1 = controlPoints[1] + let P2 = controlPoints[2] + let P3 = controlPoints[3] + + // Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves + + let x0 = (pow((1.0 - t), 3.0) * P0.x) + let x1 = (3.0 * pow(1.0 - t, 2.0) * t * P1.x) + let x2 = (3.0 * (1.0 - t) * pow(t, 2.0) * P2.x) + let x3 = (pow(t, 3.0) * P3.x) + + return x0 + x1 + x2 + x3 + } + + func derivativeCurveYValueAt(_ t: CGFloat, controlPoints: [CGPoint]) -> CGFloat { + let P0 = controlPoints[0] + let P1 = controlPoints[1] + let P2 = controlPoints[2] + let P3 = controlPoints[3] + + let dy0 = (P0.y + 3.0 * P1.y + 3.0 * P2.y - P3.y) * -3.0 + let dy1 = t * (6.0 * P0.y + 6.0 * P2.y) + let dy2 = (-3.0 * P0.y + 3.0 * P1.y) + + return dy0 * pow(t, 2.0) + dy1 + dy2 + } + + func controlPoints() -> [CGPoint] { + // Create point array to point to + var point: [Float] = [0.0, 0.0] + var pointArray = [CGPoint]() + for i in 0...3 { + self.getControlPoint(at: i, values: &point) + pointArray.append(CGPoint(x: CGFloat(point[0]), y: CGFloat(point[1]))) + } + + return pointArray + } +} + diff --git a/Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.h b/Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.h deleted file mode 100755 index f6bbaf7..0000000 --- a/Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.h +++ /dev/null @@ -1,500 +0,0 @@ - -// -// MarqueeLabel.h -// -// Created by Charles Powell on 1/31/11. -// Copyright (c) 2011-2015 Charles Powell. All rights reserved. -// - -#import - -/** An enum that defines the types of `MarqueeLabel` scrolling */ -typedef NS_ENUM(NSUInteger, MarqueeType) { - /** Scrolls left first, then back right to the original position. */ - MLLeftRight = 0, - /** Scrolls right first, then back left to the original position. */ - MLRightLeft = 1, - /** Continuously scrolls left (with a pause at the original position if animationDelay is set). See the `trailingBuffer` property to define a spacing between the repeating strings.*/ - MLContinuous = 2, - /** Continuously scrolls right (with a pause at the original position if animationDelay is set). See the `trailingBuffer` property to define a spacing between the repeating strings.*/ - MLContinuousReverse = 3, - /** Scrolls left first, then does not return to the original position. */ - MLLeft = 4, - /** Scrolls right first, then does not return to the original position. */ - MLRight = 5 -}; - - -#ifndef IBInspectable -#define IBInspectable -#endif - -/** - MarqueeLabel is a UILabel subclass adds a scrolling marquee effect when the text of a label instance outgrows the available width. Instances of `MarqueeLabel` can be configured - for label scrolling direction/looping, speed/rate, and other options. - */ - -IB_DESIGNABLE -@interface MarqueeLabel : UILabel - -//////////////////////////////////////////////////////////////////////////////// -/// @name Creating MarqueeLabels -//////////////////////////////////////////////////////////////////////////////// - -/** Returns a newly initialized `MarqueeLabel` instance. - - The default scroll duration of 7.0 seconds and fade length of 0.0 are used. - - @param frame A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. - @return An initialized `MarqueeLabel` object or nil if the object couldn't be created. -*/ - -- (instancetype)initWithFrame:(CGRect)frame; - - -/** Returns a newly initialized `MarqueeLabel` instance with the specified scroll rate and edge transparency fade length. - - You must specify a non-zero rate, and you cannot thereafter modify the rate. - - @param frame A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. - @param pixelsPerSec A rate of scroll for the label scroll animation. Must be non-zero. Note that this will be the maximum rate for ease-type animation. - @param fadeLength A length of transparency fade at the left and right edges of the `MarqueeLabel` instance's frame. - @see fadeLength - @return An initialized `MarqueeLabel` object or nil if the object couldn't be created. - */ - -- (instancetype)initWithFrame:(CGRect)frame rate:(CGFloat)pixelsPerSec andFadeLength:(CGFloat)fadeLength; - - -/** Returns a newly initialized `MarqueeLabel` instance with the specified scroll duration and edge transparency fade length. - - You must specify a non-zero duration, and you cannot thereafter modify the duration. - - @param frame A rectangle specifying the initial location and size of the view in its superview's coordinates. Text (for the given font, font size, etc.) that does not fit in this frame will automatically scroll. - @param scrollDuration A scroll duration the label scroll animation. Must be non-zero. This will be the duration that the animation takes for one-half of the scroll cycle in the case of left-right and right-left marquee types, and for one loop of a continuous marquee type. - @param fadeLength A length of transparency fade at the left and right edges of the `MarqueeLabel` instance's frame. - @see fadeLength - @return An initialized `MarqueeLabel` object or nil if the object couldn't be created. - */ - -- (instancetype)initWithFrame:(CGRect)frame duration:(NSTimeInterval)scrollDuration andFadeLength:(CGFloat)fadeLength; - - -/** Resizes the view to the minimum size necessary to fully enclose the current text (i.e. without scrolling), up to the maximum size specified. - - The current origin of the frame is retained. - - @param maxSize The maximum size up to which the view should be resized. Passing `CGSizeZero` will result in no maximum size limit. - @param adjustHeight A boolean that can be used to indicate if the view's height should also be adjusted. Note that this has no impact on scrolling. - */ -- (void)minimizeLabelFrameWithMaximumSize:(CGSize)maxSize adjustHeight:(BOOL)adjustHeight; - - -//////////////////////////////////////////////////////////////////////////////// -/// @name Configuration Options -//////////////////////////////////////////////////////////////////////////////// - -/** Specifies the animation curve used in the scrolling motion of the labels. - - Allowable options: - - - `UIViewAnimationOptionCurveEaseInOut` - - `UIViewAnimationOptionCurveEaseIn` - - `UIViewAnimationOptionCurveEaseOut` - - `UIViewAnimationOptionCurveLinear` - - Defaults to `UIViewAnimationOptionCurveEaseInOut`. - */ - -@property (nonatomic, assign) UIViewAnimationOptions animationCurve; - - -/** A boolean property that sets whether the `MarqueeLabel` should behave like a normal UILabel. - - When set to `YES` the `MarqueeLabel` will behave like a normal UILabel, and will not begin scrolling when the text is - larger than the specified frame. The change takes effect immediately, removing any in-flight animation as well as any - current edge fade. Note that the `MarqueeLabel` will respect the current values of the `lineBreakMode` and `textAlignment` - properties while labelized. - - To simply prevent automatic scrolling, use the `holdScrolling` property. - - Defaults to `NO`. - - @see holdScrolling - @see lineBreakMode - @warning The label will not automatically scroll when this property is set to `YES`. - @warning The UILabel default setting for the `lineBreakMode` property is `NSLineBreakByTruncatingTail`, which truncates - the text adds an ellipsis glyph (...). Set the `lineBreakMode` property to `NSLineBreakByClipping` in order to avoid the - ellipsis, especially if using an edge transparency fade. - */ - -@property (nonatomic, assign) IBInspectable BOOL labelize; - - -/** A boolean property that sets whether the `MarqueeLabel` should hold (prevent) label scrolling. - - When set to `YES`, the `MarqueeLabel` will not automatically scroll even its text is larger than the specified frame, - although the specified edge fades will remain. - - To set the `MarqueeLabel` to act like a normal UILabel, use the `labelize` property. - - Defaults to `NO`. - - @see labelize - @warning The label will not automatically scroll when this property is set to `YES`. - */ - -@property (nonatomic, assign) IBInspectable BOOL holdScrolling; - - -/** A boolean property that sets whether the `MarqueeLabel` should only begin a scroll when tapped. - - If this property is set to `YES`, the `MarqueeLabel` will begin a scroll animation cycle only when tapped. The label will - not automatically being a scroll. This setting overrides the setting of the `holdScrolling` property. - - Defaults to `NO` . - - @warning The label will not automatically scroll when this property is set to `YES`. - @see holdScrolling - */ - -@property (nonatomic, assign) IBInspectable BOOL tapToScroll; - - -/** Defines the direction and method in which the `MarqueeLabel` instance scrolls. - - `MarqueeLabel` supports four types of scrolling: `MLLeftRight`, `MLRightLeft`, `MLContinuous`, and `MLContinuousReverse`. - - Given the nature of how text direction works, the options for the `marqueeType` property require specific text alignments - and will set the textAlignment property accordingly. - - - `MLLeftRight` type is ONLY compatible with a label text alignment of `NSTextAlignmentLeft`. - - `MLRightLeft` type is ONLY compatible with a label text alignment of `NSTextAlignmentRight`. - - `MLContinuous` does not require a text alignment (it is effectively centered). - - `MLContinuousReverse` does not require a text alignment (it is effectively centered). - - Defaults to `MLLeftRight`. - - @see MarqueeType - @see textAlignment - */ - -#if TARGET_INTERFACE_BUILDER -@property (nonatomic, assign) IBInspectable NSInteger marqueeType; -#else -@property (nonatomic, assign) MarqueeType marqueeType; -#endif - -/** Defines the duration of the scrolling animation. - - This property sets the amount of time it will take for the scrolling animation to complete a - scrolling cycle. Note that for `MLLeftRight` and `MLRightLeft`, a cycle consists of the animation away, - a pause (if a delay is specified), and the animation back to the original position. - - Setting this property will automatically override any value previously set to the `rate` property, and the `rate` - property will be set to `0.0`. - - @see rate - */ - -@property (nonatomic, assign) IBInspectable CGFloat scrollDuration; - - -/** Defines the rate at which the label will scroll, in pixels per second. - - Setting this property will automatically override any value previousy set to the `scrollDuration` property, and the - `scrollDuration` property will be set to `0.0`. Note that this is the rate at which the label would scroll if it - moved at a constant speed - with other animation curves the rate will be slightly different. - - @see scrollDuration - */ - -@property (nonatomic, assign) IBInspectable CGFloat rate; - - -/** A buffer (offset) between the leading edge of the label text and the label frame. - - This property adds additional space between the leading edge of the label text and the label frame. The - leading edge is the edge of the label text facing the direction of scroll (i.e. the edge that animates - offscreen first during scrolling). - - Defaults to `0`. - - @note The value set to this property affects label positioning at all times (including when `labelize` is set to `YES`), - including when the text string length is short enough that the label does not need to scroll. - - @note For `MLContinuous`-type labels, the smallest value of `leadingBuffer`, 'trailingBuffer`, and `fadeLength` - is used as spacing between the two label instances. Zero is an allowable value for all three properties. - - @see trailingBuffer - @since Available in 2.1.0 and later. - */ - -@property (nonatomic, assign) IBInspectable CGFloat leadingBuffer; - - -/** A buffer (offset) between the trailing edge of the label text and the label frame. - - This property adds additional space (buffer) between the trailing edge of the label text and the label frame. The - trailing edge is the edge of the label text facing away from the direction of scroll (i.e. the edge that animates - offscreen last during scrolling). - - Defaults to `0`. - - @note For `MLContinuous`-type labels, the smallest value of `leadingBuffer`, 'trailingBuffer`, and `fadeLength` - is used as spacing between the two label instances. Zero is an allowable value for all three properties. - - @note The value set to this property has no effect when the `labelize` property is set to `YES`. - - @see leadingBuffer - @since Available in 2.1.0 and later. - */ - -@property (nonatomic, assign) IBInspectable CGFloat trailingBuffer; - - -/** - @deprecated Use `trailingBuffer` instead. Values set to this property are simply forwarded to `trailingBuffer`. - */ - -@property (nonatomic, assign) CGFloat continuousMarqueeExtraBuffer __deprecated_msg("Use trailingBuffer instead."); - - -/** The length of transparency fade at the left and right edges of the `MarqueeLabel` instance's frame. - - This propery sets the size (in points) of the view edge transparency fades on the left and right edges of a `MarqueeLabel`. The - transparency fades from an alpha of 1.0 (fully visible) to 0.0 (fully transparent) over this distance. Values set to this property - will be sanitized to prevent a fade length greater than 1/2 of the frame width. - - Defaults to `0`. - */ - -@property (nonatomic, assign) IBInspectable CGFloat fadeLength; - - -/** The length of delay in seconds that the label pauses at the completion of a scroll. */ - -@property (nonatomic, assign) IBInspectable CGFloat animationDelay; - - -/** The read-only duration of the scroll animation (not including delay). - - The value of this property is calculated when using the `scrollRate` property to set label animation speed. The value of this property - is equal to the value of `scrollDuration` property when using the `scrollDuration` property to set label animation speed. - - @see scrollDuration - @see scrollRate - */ - -@property (nonatomic, readonly) NSTimeInterval animationDuration; - - - -//////////////////////////////////////////////////////////////////////////////// -/// @name Animation control -//////////////////////////////////////////////////////////////////////////////// - -/** Immediately resets the label to the home position, cancelling any in-flight scroll animation, and restarts the scroll animation if the appropriate conditions are met. - - @see triggerScrollStart - */ - -- (void)restartLabel; - - -/** Immediately resets the label to the home position, cancelling any in-flight scroll animation. - - The text is immediately returned to the home position. Scrolling will not resume automatically after a call to this method. - To re-initiate scrolling use a call to `restartLabel` or `triggerScrollStart`, or make a change to a UILabel property such as text, bounds/frame, - font, font size, etc. - - @see restartLabel - @see triggerScrollStart - @since Available in 2.4.0 and later. - */ - -- (void)shutdownLabel; - - -/** - @deprecated Use `resetLabel:` instead. - */ - -- (void)resetLabel __deprecated_msg("Use resetLabel instead"); - - -/** Pauses the text scrolling animation, at any point during an in-progress animation. - - @note This method has no effect if a scroll animation is NOT already in progress. To prevent automatic scrolling on a newly-initialized label prior to its presentation onscreen, see the `holdScrolling` property. - - @see holdScrolling - @see unpauseLabel - */ - -- (void)pauseLabel; - - -/** Un-pauses a previously paused text scrolling animation. This method has no effect if the label was not previously paused using `pauseLabel`. - - @see pauseLabel - */ - -- (void)unpauseLabel; - - -/** Overrides any non-size condition which is preventing the receiver from automatically scrolling, and begins a scroll animation. - - Currently the only non-size conditions which can prevent a label from scrolling are the `tapToScroll` and `holdScrolling` properties. This - method will not force a label with a string that fits inside the label bounds (i.e. that would not automatically scroll) to begin a scroll - animation. - - Upon the completion of the first forced scroll animation, the receiver will not automatically continue to scroll unless the conditions - preventing scrolling have been removed. - - @note This method has no effect if called during an already in-flight scroll animation. - - @see restartLabel - @since Available in 2.2.0 and later. - */ - -- (void)triggerScrollStart; - - - -//////////////////////////////////////////////////////////////////////////////// -/// @name Animation Status -//////////////////////////////////////////////////////////////////////////////// - -/** Called when the label animation is about to begin. - - The default implementation of this method does nothing. Subclasses may override this method in order to perform any custom actions just as - the label animation begins. This is only called in the event that the conditions for scrolling to begin are met. - - @since Available in 1.5.0 and later. - */ - -- (void)labelWillBeginScroll; - - -/** Called when the label animation has finished, and the label is at the home position. - - The default implementation of this method does nothing. Subclasses may override this method in order to perform any custom actions jas as - the label animation completes, and before the next animation would begin (assuming the scroll conditions are met). - - @param finished A Boolean that indicates whether or not the scroll animation actually finished before the completion handler was called. - @since Available in 1.5.0 and later. - - @warning This method will be called, and the `finished` parameter will be `NO`, when any property changes are made that would cause the label - scrolling to be automatically reset. This includes changes to label text and font/font size changes. - */ - -- (void)labelReturnedToHome:(BOOL)finished; - - -/** A boolean property that indicates if the label's scroll animation has been paused. - - @see pauseLabel - @see unpauseLabel - */ - -@property (nonatomic, assign, readonly) BOOL isPaused; - - -/** A boolean property that indicates if the label is currently away from the home location. - - The "home" location is the traditional location of `UILabel` text. This property essentially reflects if a scroll animation is underway. - */ - -@property (nonatomic, assign, readonly) BOOL awayFromHome; - - - -//////////////////////////////////////////////////////////////////////////////// -/// @name Bulk-manipulation Methods -//////////////////////////////////////////////////////////////////////////////// - -/** Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. - - This method sends a `NSNotification` to all `MarqueeLabel` instances with the specified view controller in their next responder chain. - The scrolling animation of these instances will be automatically restarted. This is equivalent to calling `restartLabel` on all affected - instances. - - There is currently no functional difference between this method and `controllerViewDidAppear:` or `controllerViewWillAppear:`. The methods may - be used interchangeably. - - @warning View controllers that appear with animation (such as from underneath a modal-style controller) can cause some `MarqueeLabel` text - position "jumping" when this method is used in `viewDidAppear` if scroll animations are already underway. Use this method inside `viewWillAppear:` - instead to avoid this problem. - - @warning This method may not function properly if passed the parent view controller when using view controller containment. - - @param controller The view controller that has appeared. - @see restartLabel - @see controllerViewDidAppear: - @see controllerViewWillAppear: - @since Available in 1.3.1 and later. - */ - -+ (void)restartLabelsOfController:(UIViewController *)controller; - - -/** Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. - - Alternative to `restartLabelsOfController:`. This method is retained for backwards compatibility and future enhancements. - - @param controller The view controller that has appeared. - @see restartLabel - @see controllerViewWillAppear: - @since Available in 1.2.7 and later. - */ - -+ (void)controllerViewDidAppear:(UIViewController *)controller; - - -/** Convenience method to restart all `MarqueeLabel` instances that have the specified view controller in their next responder chain. - - Alternative to `restartLabelsOfController:`. This method is retained for backwards compatibility and future enhancements. - - @param controller The view controller that has appeared. - @see restartLabel - @see controllerViewDidAppear: - @since Available in 1.2.8 and later. - */ - -+ (void)controllerViewWillAppear:(UIViewController *)controller; - - -/** - @deprecated Use `controllerViewDidAppear:` instead. - */ - -+ (void)controllerViewAppearing:(UIViewController *)controller __deprecated_msg("Use controllerViewDidAppear: instead."); - - -/** Labelizes all `MarqueeLabel` instances that have the specified view controller in their next responder chain. - - This method sends an `NSNotification` to all `MarqueeLabel` instances with the specified view controller in their next - responder chain. The `labelize` property of these `MarqueeLabel` instances will be set to `YES`. - - @param controller The view controller for which all `MarqueeLabel` instances should be labelized. - @see labelize - */ - -+ (void)controllerLabelsShouldLabelize:(UIViewController *)controller; - - -/** De-Labelizes all `MarqueeLabel` instances that have the specified view controller in their next responder chain. - - This method sends an `NSNotification` to all `MarqueeLabel` instances with the specified view controller in their next - responder chain. The `labelize` property of these `MarqueeLabel` instances will be set to `NO` . - - @param controller The view controller for which all `MarqueeLabel` instances should be de-labelized. - @see labelize - */ - -+ (void)controllerLabelsShouldAnimate:(UIViewController *)controller; - - -@end - - diff --git a/Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.m b/Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.m deleted file mode 100755 index 680d85b..0000000 --- a/Pods/MarqueeLabel/Sources/ObjC/MarqueeLabel.m +++ /dev/null @@ -1,1682 +0,0 @@ - -// -// MarqueeLabel.m -// -// Created by Charles Powell on 1/31/11. -// Copyright (c) 2011-2015 Charles Powell. All rights reserved. -// - -#import "MarqueeLabel.h" -#import - -// Notification strings -NSString *const kMarqueeLabelControllerRestartNotification = @"MarqueeLabelViewControllerRestart"; -NSString *const kMarqueeLabelShouldLabelizeNotification = @"MarqueeLabelShouldLabelizeNotification"; -NSString *const kMarqueeLabelShouldAnimateNotification = @"MarqueeLabelShouldAnimateNotification"; -NSString *const kMarqueeLabelAnimationCompletionBlock = @"MarqueeLabelAnimationCompletionBlock"; - -// Animation completion block -typedef void(^MLAnimationCompletionBlock)(BOOL finished); - -// iOS Version check for iOS 8.0.0 -#define SYSTEM_VERSION_IS_8_0_X ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"8.0"]) - -// Define "a long time" for MLLeft and MLRight types -#define CGFLOAT_LONG_DURATION 60*60*24*365 // One year in seconds - -// Helpers -@interface GradientSetupAnimation : CABasicAnimation -@end - -@interface UIView (MarqueeLabelHelpers) -- (UIViewController *)firstAvailableViewController; -- (id)traverseResponderChainForFirstViewController; -@end - -@interface CAMediaTimingFunction (MarqueeLabelHelpers) -- (NSArray *)controlPoints; -- (CGFloat)durationPercentageForPositionPercentage:(CGFloat)positionPercentage withDuration:(NSTimeInterval)duration; -@end - -@interface MarqueeLabel() - -@property (nonatomic, strong) UILabel *subLabel; - -@property (nonatomic, assign) NSTimeInterval animationDuration; -@property (nonatomic, assign, readonly) BOOL labelShouldScroll; -@property (nonatomic, weak) UITapGestureRecognizer *tapRecognizer; -@property (nonatomic, assign) CGRect homeLabelFrame; -@property (nonatomic, assign) CGFloat awayOffset; -@property (nonatomic, assign, readwrite) BOOL isPaused; - -// Support -@property (nonatomic, copy) MLAnimationCompletionBlock scrollCompletionBlock; -@property (nonatomic, strong) NSArray *gradientColors; -CGPoint MLOffsetCGPoint(CGPoint point, CGFloat offset); - -@end - - -@implementation MarqueeLabel - -#pragma mark - Class Methods and handlers - -+ (void)restartLabelsOfController:(UIViewController *)controller { - [MarqueeLabel notifyController:controller - withMessage:kMarqueeLabelControllerRestartNotification]; -} - -+ (void)controllerViewWillAppear:(UIViewController *)controller { - [MarqueeLabel restartLabelsOfController:controller]; -} - -+ (void)controllerViewDidAppear:(UIViewController *)controller { - [MarqueeLabel restartLabelsOfController:controller]; -} - -+ (void)controllerViewAppearing:(UIViewController *)controller { - [MarqueeLabel restartLabelsOfController:controller]; -} - -+ (void)controllerLabelsShouldLabelize:(UIViewController *)controller { - [MarqueeLabel notifyController:controller - withMessage:kMarqueeLabelShouldLabelizeNotification]; -} - -+ (void)controllerLabelsShouldAnimate:(UIViewController *)controller { - [MarqueeLabel notifyController:controller - withMessage:kMarqueeLabelShouldAnimateNotification]; -} - -+ (void)notifyController:(UIViewController *)controller withMessage:(NSString *)message -{ - if (controller && message) { - [[NSNotificationCenter defaultCenter] postNotificationName:message - object:nil - userInfo:[NSDictionary dictionaryWithObject:controller - forKey:@"controller"]]; - } -} - -- (void)viewControllerShouldRestart:(NSNotification *)notification { - UIViewController *controller = [[notification userInfo] objectForKey:@"controller"]; - if (controller == [self firstAvailableViewController]) { - [self restartLabel]; - } -} - -- (void)labelsShouldLabelize:(NSNotification *)notification { - UIViewController *controller = [[notification userInfo] objectForKey:@"controller"]; - if (controller == [self firstAvailableViewController]) { - self.labelize = YES; - } -} - -- (void)labelsShouldAnimate:(NSNotification *)notification { - UIViewController *controller = [[notification userInfo] objectForKey:@"controller"]; - if (controller == [self firstAvailableViewController]) { - self.labelize = NO; - } -} - -#pragma mark - Initialization and Label Config - -- (id)initWithFrame:(CGRect)frame { - return [self initWithFrame:frame duration:7.0 andFadeLength:0.0]; -} - -- (id)initWithFrame:(CGRect)frame duration:(NSTimeInterval)aLengthOfScroll andFadeLength:(CGFloat)aFadeLength { - self = [super initWithFrame:frame]; - if (self) { - [self setupLabel]; - - _scrollDuration = aLengthOfScroll; - self.fadeLength = MIN(aFadeLength, frame.size.width/2); - } - return self; -} - -- (id)initWithFrame:(CGRect)frame rate:(CGFloat)pixelsPerSec andFadeLength:(CGFloat)aFadeLength { - self = [super initWithFrame:frame]; - if (self) { - [self setupLabel]; - - _rate = pixelsPerSec; - self.fadeLength = MIN(aFadeLength, frame.size.width/2); - } - return self; -} - -- (id)initWithCoder:(NSCoder *)aDecoder { - self = [super initWithCoder:aDecoder]; - if (self) { - [self setupLabel]; - - if (self.scrollDuration == 0) { - self.scrollDuration = 7.0; - } - } - return self; -} - -- (void)awakeFromNib { - [super awakeFromNib]; - [self forwardPropertiesToSubLabel]; -} - -- (void)prepareForInterfaceBuilder { - [super prepareForInterfaceBuilder]; - [self forwardPropertiesToSubLabel]; -} - -+ (Class)layerClass { - return [CAReplicatorLayer class]; -} - -- (CAReplicatorLayer *)repliLayer { - return (CAReplicatorLayer *)self.layer; -} - -- (CAGradientLayer *)maskLayer { - return (CAGradientLayer *)self.layer.mask; -} - -- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx { - // Do NOT call super, to prevent UILabel superclass from drawing into context - // Label drawing is handled by sublabel and CAReplicatorLayer layer class - - // Draw only background color - CGContextSetFillColorWithColor(ctx, self.backgroundColor.CGColor); - CGContextFillRect(ctx, layer.bounds); -} - -- (void)forwardPropertiesToSubLabel { - /* - Note that this method is currently ONLY called from awakeFromNib, i.e. when - text properties are set via a Storyboard. As the Storyboard/IB doesn't currently - support attributed strings, there's no need to "forward" the super attributedString value. - */ - - // Since we're a UILabel, we actually do implement all of UILabel's properties. - // We don't care about these values, we just want to forward them on to our sublabel. - NSArray *properties = @[@"baselineAdjustment", @"enabled", @"highlighted", @"highlightedTextColor", - @"minimumFontSize", @"textAlignment", - @"userInteractionEnabled", @"adjustsFontSizeToFitWidth", - @"lineBreakMode", @"numberOfLines", @"contentMode"]; - - // Iterate through properties - self.subLabel.text = super.text; - self.subLabel.font = super.font; - self.subLabel.textColor = super.textColor; - self.subLabel.backgroundColor = (super.backgroundColor == nil ? [UIColor clearColor] : super.backgroundColor); - self.subLabel.shadowColor = super.shadowColor; - self.subLabel.shadowOffset = super.shadowOffset; - for (NSString *property in properties) { - id val = [super valueForKey:property]; - [self.subLabel setValue:val forKey:property]; - } -} - -- (void)setupLabel { - - // Basic UILabel options override - self.clipsToBounds = YES; - self.numberOfLines = 1; - - // Create first sublabel - self.subLabel = [[UILabel alloc] initWithFrame:self.bounds]; - self.subLabel.tag = 700; - self.subLabel.layer.anchorPoint = CGPointMake(0.0f, 0.0f); - - [self addSubview:self.subLabel]; - - // Setup default values - _marqueeType = MLContinuous; - _awayOffset = 0.0f; - _animationCurve = UIViewAnimationOptionCurveLinear; - _labelize = NO; - _holdScrolling = NO; - _tapToScroll = NO; - _isPaused = NO; - _fadeLength = 0.0f; - _animationDelay = 1.0; - _animationDuration = 0.0f; - _leadingBuffer = 0.0f; - _trailingBuffer = 0.0f; - - // Add notification observers - // Custom class notifications - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewControllerShouldRestart:) name:kMarqueeLabelControllerRestartNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(labelsShouldLabelize:) name:kMarqueeLabelShouldLabelizeNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(labelsShouldAnimate:) name:kMarqueeLabelShouldAnimateNotification object:nil]; - - // UIApplication state notifications - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restartLabel) name:UIApplicationDidBecomeActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdownLabel) name:UIApplicationDidEnterBackgroundNotification object:nil]; -} - -- (void)minimizeLabelFrameWithMaximumSize:(CGSize)maxSize adjustHeight:(BOOL)adjustHeight { - if (self.subLabel.text != nil) { - // Calculate text size - if (CGSizeEqualToSize(maxSize, CGSizeZero)) { - maxSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); - } - CGSize minimumLabelSize = [self subLabelSize]; - - // Adjust for fade length - CGSize minimumSize = CGSizeMake(minimumLabelSize.width + (self.fadeLength * 2), minimumLabelSize.height); - - // Find minimum size of options - minimumSize = CGSizeMake(MIN(minimumSize.width, maxSize.width), MIN(minimumSize.height, maxSize.height)); - - // Apply to frame - self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, minimumSize.width, (adjustHeight ? minimumSize.height : self.frame.size.height)); - } -} - --(void)didMoveToSuperview { - [self updateSublabel]; -} - -#pragma mark - MarqueeLabel Heavy Lifting - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - [self updateSublabel]; -} - -- (void)willMoveToWindow:(UIWindow *)newWindow { - if (!newWindow) { - [self shutdownLabel]; - } -} - -- (void)didMoveToWindow { - if (!self.window) { - [self shutdownLabel]; - } else { - [self updateSublabel]; - } -} - -- (void)updateSublabel { - [self updateSublabelAndBeginScroll:YES]; -} - -- (void)updateSublabelAndBeginScroll:(BOOL)beginScroll { - if (!self.subLabel.text || !self.superview) { - return; - } - - // Calculate expected size - CGSize expectedLabelSize = [self subLabelSize]; - - - // Invalidate intrinsic size - [self invalidateIntrinsicContentSize]; - - // Move to home - [self returnLabelToOriginImmediately]; - - // Configure gradient for the current condition - [self applyGradientMaskForFadeLength:self.fadeLength animated:YES]; - - // Check if label should scroll - // Can be because: 1) text fits, or 2) labelization - // The holdScrolling property does NOT affect this - if (!self.labelShouldScroll) { - // Set text alignment and break mode to act like normal label - self.subLabel.textAlignment = [super textAlignment]; - self.subLabel.lineBreakMode = [super lineBreakMode]; - - CGRect labelFrame, unusedFrame; - switch (self.marqueeType) { - case MLContinuousReverse: - case MLRightLeft: - case MLRight: - CGRectDivide(self.bounds, &unusedFrame, &labelFrame, self.leadingBuffer, CGRectMaxXEdge); - labelFrame = CGRectIntegral(labelFrame); - break; - - default: - labelFrame = CGRectIntegral(CGRectMake(self.leadingBuffer, 0.0f, self.bounds.size.width - self.leadingBuffer, self.bounds.size.height)); - break; - } - - self.homeLabelFrame = labelFrame; - self.awayOffset = 0.0f; - - // Remove an additional sublabels (for continuous types) - self.repliLayer.instanceCount = 1; - - // Set sublabel frame calculated labelFrame - self.subLabel.frame = labelFrame; - - // Remove fade, as by definition none is needed in this case - [self removeGradientMask]; - - return; - } - - // Label DOES need to scroll - - [self.subLabel setLineBreakMode:NSLineBreakByClipping]; - - // Spacing between primary and second sublabel must be at least equal to leadingBuffer, and at least equal to the fadeLength - CGFloat minTrailing = MAX(MAX(self.leadingBuffer, self.trailingBuffer), self.fadeLength); - - switch (self.marqueeType) { - case MLContinuous: - case MLContinuousReverse: - { - if (self.marqueeType == MLContinuous) { - self.homeLabelFrame = CGRectIntegral(CGRectMake(self.leadingBuffer, 0.0f, expectedLabelSize.width, self.bounds.size.height)); - self.awayOffset = -(self.homeLabelFrame.size.width + minTrailing); - } else { - self.homeLabelFrame = CGRectIntegral(CGRectMake(self.bounds.size.width - (expectedLabelSize.width + self.leadingBuffer), 0.0f, expectedLabelSize.width, self.bounds.size.height)); - self.awayOffset = (self.homeLabelFrame.size.width + minTrailing); - } - - self.subLabel.frame = self.homeLabelFrame; - - // Configure replication - self.repliLayer.instanceCount = 2; - self.repliLayer.instanceTransform = CATransform3DMakeTranslation(-self.awayOffset, 0.0, 0.0); - - // Recompute the animation duration - self.animationDuration = (self.rate != 0) ? ((NSTimeInterval) fabs(self.awayOffset) / self.rate) : (self.scrollDuration); - - break; - } - - case MLRightLeft: - case MLRight: - { - self.homeLabelFrame = CGRectIntegral(CGRectMake(self.bounds.size.width - (expectedLabelSize.width + self.leadingBuffer), 0.0f, expectedLabelSize.width, self.bounds.size.height)); - self.awayOffset = (expectedLabelSize.width + self.trailingBuffer + self.leadingBuffer) - self.bounds.size.width; - - // Calculate animation duration - self.animationDuration = (self.rate != 0) ? (NSTimeInterval)fabs(self.awayOffset / self.rate) : (self.scrollDuration); - - // Set frame and text - self.subLabel.frame = self.homeLabelFrame; - - // Remove any replication - self.repliLayer.instanceCount = 1; - - // Enforce text alignment for this type - self.subLabel.textAlignment = NSTextAlignmentRight; - - break; - } - - case MLLeftRight: - case MLLeft: - { - self.homeLabelFrame = CGRectIntegral(CGRectMake(self.leadingBuffer, 0.0f, expectedLabelSize.width, self.bounds.size.height)); - self.awayOffset = self.bounds.size.width - (expectedLabelSize.width + self.leadingBuffer + self.trailingBuffer); - - // Calculate animation duration - self.animationDuration = (self.rate != 0) ? (NSTimeInterval)fabs(self.awayOffset / self.rate) : (self.scrollDuration); - - // Set frame - self.subLabel.frame = self.homeLabelFrame; - - // Remove any replication - self.repliLayer.instanceCount = 1; - - // Enforce text alignment for this type - self.subLabel.textAlignment = NSTextAlignmentLeft; - - break; - } - - default: - { - // Something strange has happened - self.homeLabelFrame = CGRectZero; - self.awayOffset = 0.0f; - - // Do not attempt to begin scroll - return; - break; - } - - } //end of marqueeType switch - - if (!self.tapToScroll && !self.holdScrolling && beginScroll) { - [self beginScroll]; - } -} - -- (CGSize)subLabelSize { - // Calculate expected size - CGSize expectedLabelSize = CGSizeZero; - CGSize maximumLabelSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); - - // Get size of subLabel - expectedLabelSize = [self.subLabel sizeThatFits:maximumLabelSize]; -#ifdef TARGET_OS_IOS - // Sanitize width to 5461.0f (largest width a UILabel will draw on an iPhone 6S Plus) - expectedLabelSize.width = MIN(expectedLabelSize.width, 5461.0f); -#elif TARGET_OS_TV - // Sanitize width to 16384.0 (largest width a UILabel will draw on tvOS) - expectedLabelSize.width = MIN(expectedLabelSize.width, 16384.0f); -#endif - // Adjust to own height (make text baseline match normal label) - expectedLabelSize.height = self.bounds.size.height; - - return expectedLabelSize; -} - -- (CGSize)sizeThatFits:(CGSize)size { - CGSize fitSize = [self.subLabel sizeThatFits:size]; - fitSize.width += self.leadingBuffer; - return fitSize; -} - -#pragma mark - Animation Handlers - -- (BOOL)labelShouldScroll { - BOOL stringLength = ([self.subLabel.text length] > 0); - if (!stringLength) { - return NO; - } - - BOOL labelTooLarge = ([self subLabelSize].width + self.leadingBuffer > self.bounds.size.width + FLT_EPSILON); - BOOL animationHasDuration = (self.scrollDuration > 0.0f || self.rate > 0.0f); - return (!self.labelize && labelTooLarge && animationHasDuration); -} - -- (BOOL)labelReadyForScroll { - // Check if we have a superview - if (!self.superview) { - return NO; - } - - if (!self.window) { - return NO; - } - - // Check if our view controller is ready - UIViewController *viewController = [self firstAvailableViewController]; - if (!viewController.isViewLoaded) { - return NO; - } - - return YES; -} - -- (void)beginScroll { - [self beginScrollWithDelay:YES]; -} - -- (void)beginScrollWithDelay:(BOOL)delay { - switch (self.marqueeType) { - case MLContinuous: - case MLContinuousReverse: - [self scrollContinuousWithInterval:self.animationDuration after:(delay ? self.animationDelay : 0.0)]; - break; - case MLLeft: - case MLRight: - [self scrollAwayWithInterval:self.animationDuration delayAmount:(delay ? self.animationDelay : 0.0) shouldReturn:NO]; - break; - default: - [self scrollAwayWithInterval:self.animationDuration]; - break; - } -} - -- (void)returnLabelToOriginImmediately { - // Remove gradient animations - [self.layer.mask removeAllAnimations]; - - // Remove sublabel position animations - [self.subLabel.layer removeAllAnimations]; - - // Remove compeltion blocks - self.scrollCompletionBlock = nil; -} - -- (void)scrollAwayWithInterval:(NSTimeInterval)interval { - [self scrollAwayWithInterval:interval delay:YES]; -} - -- (void)scrollAwayWithInterval:(NSTimeInterval)interval delay:(BOOL)delay { - [self scrollAwayWithInterval:interval delayAmount:(delay ? self.animationDelay : 0.0) shouldReturn:YES]; -} - -- (void)scrollAwayWithInterval:(NSTimeInterval)interval delayAmount:(NSTimeInterval)delayAmount shouldReturn:(BOOL)shouldReturn { - // Check for conditions which would prevent scrolling - if (![self labelReadyForScroll]) { - return; - } - - // Return labels to home (cancel any animations) - [self returnLabelToOriginImmediately]; - - // Call pre-animation method - [self labelWillBeginScroll]; - - // Animate - [CATransaction begin]; - - // Set Duration - [CATransaction setAnimationDuration:(!shouldReturn ? CGFLOAT_MAX : 2.0 * (delayAmount + interval))]; - - // Create animation for gradient, if needed - if (self.fadeLength != 0.0f) { - CAKeyframeAnimation *gradAnim = [self keyFrameAnimationForGradientFadeLength:self.fadeLength - interval:interval - delay:delayAmount]; - [self.layer.mask addAnimation:gradAnim forKey:@"gradient"]; - } - - __weak __typeof__(self) weakSelf = self; - self.scrollCompletionBlock = ^(BOOL finished) { - if (!weakSelf) { - return; - } - - // Call returned home method - [weakSelf labelReturnedToHome:YES]; - - // Check to ensure that: - // 1) The instance is still attached to a window - this completion block is called for - // many reasons, including if the animation is removed due to the view being removed - // from the UIWindow (typically when the view controller is no longer the "top" view) - if (!weakSelf.window) { - return; - } - // 2) We don't double fire if an animation already exists - if ([weakSelf.subLabel.layer animationForKey:@"position"]) { - return; - } - // 3) We don't not start automatically if the animation was unexpectedly interrupted - if (!finished) { - // Do not continue into the next loop - return; - } - // 4) A completion block still exists for the NEXT loop. A notable case here is if - // returnLabelToHome was called during a subclass's labelReturnToHome function - if (!weakSelf.scrollCompletionBlock) { - return; - } - - // Begin again, if conditions met - if (weakSelf.labelShouldScroll && !weakSelf.tapToScroll && !weakSelf.holdScrolling) { - [weakSelf scrollAwayWithInterval:interval delayAmount:delayAmount shouldReturn:shouldReturn]; - } - }; - - - // Create animation for position - CGPoint homeOrigin = self.homeLabelFrame.origin; - CGPoint awayOrigin = MLOffsetCGPoint(self.homeLabelFrame.origin, self.awayOffset); - - NSArray *values = nil; - switch (self.marqueeType) { - case MLLeft: - case MLRight: - values = @[[NSValue valueWithCGPoint:homeOrigin], // Initial location, home - [NSValue valueWithCGPoint:homeOrigin], // Initial delay, at home - [NSValue valueWithCGPoint:awayOrigin], // Animation to away - [NSValue valueWithCGPoint:awayOrigin]]; // Delay at away - break; - - default: - values = @[[NSValue valueWithCGPoint:homeOrigin], // Initial location, home - [NSValue valueWithCGPoint:homeOrigin], // Initial delay, at home - [NSValue valueWithCGPoint:awayOrigin], // Animation to away - [NSValue valueWithCGPoint:awayOrigin], // Delay at away - [NSValue valueWithCGPoint:homeOrigin]]; // Animation to home - break; - } - - CAKeyframeAnimation *awayAnim = [self keyFrameAnimationForProperty:@"position" - values:values - interval:interval - delay:delayAmount]; - // Add completion block - [awayAnim setValue:@(YES) forKey:kMarqueeLabelAnimationCompletionBlock]; - - // Add animation - [self.subLabel.layer addAnimation:awayAnim forKey:@"position"]; - - [CATransaction commit]; -} - -- (void)scrollContinuousWithInterval:(NSTimeInterval)interval after:(NSTimeInterval)delayAmount { - [self scrollContinuousWithInterval:interval after:delayAmount labelAnimation:nil gradientAnimation:nil]; -} - -- (void)scrollContinuousWithInterval:(NSTimeInterval)interval - after:(NSTimeInterval)delayAmount - labelAnimation:(CAKeyframeAnimation *)labelAnimation - gradientAnimation:(CAKeyframeAnimation *)gradientAnimation { - // Check for conditions which would prevent scrolling - if (![self labelReadyForScroll]) { - return; - } - - // Return labels to home (cancel any animations) - [self returnLabelToOriginImmediately]; - - // Call pre-animation method - [self labelWillBeginScroll]; - - // Animate - [CATransaction begin]; - - // Set Duration - [CATransaction setAnimationDuration:(delayAmount + interval)]; - - // Create animation for gradient, if needed - if (self.fadeLength != 0.0f) { - if (!gradientAnimation) { - gradientAnimation = [self keyFrameAnimationForGradientFadeLength:self.fadeLength - interval:interval - delay:delayAmount]; - } - [self.layer.mask addAnimation:gradientAnimation forKey:@"gradient"]; - } - - // Create animation for sublabel positions, if needed - if (!labelAnimation) { - CGPoint homeOrigin = self.homeLabelFrame.origin; - CGPoint awayOrigin = MLOffsetCGPoint(self.homeLabelFrame.origin, self.awayOffset); - NSArray *values = @[[NSValue valueWithCGPoint:homeOrigin], // Initial location, home - [NSValue valueWithCGPoint:homeOrigin], // Initial delay, at home - [NSValue valueWithCGPoint:awayOrigin]]; // Animation to home - - labelAnimation = [self keyFrameAnimationForProperty:@"position" - values:values - interval:interval - delay:delayAmount]; - } - - __weak __typeof__(self) weakSelf = self; - self.scrollCompletionBlock = ^(BOOL finished) { - if (!finished || !weakSelf) { - // Do not continue into the next loop - return; - } - // Call returned home method - [weakSelf labelReturnedToHome:YES]; - // Check to ensure that: - // 1) We don't double fire if an animation already exists - // 2) The instance is still attached to a window - this completion block is called for - // many reasons, including if the animation is removed due to the view being removed - // from the UIWindow (typically when the view controller is no longer the "top" view) - if (weakSelf.window && ![weakSelf.subLabel.layer animationForKey:@"position"]) { - // Begin again, if conditions met - if (weakSelf.labelShouldScroll && !weakSelf.tapToScroll && !weakSelf.holdScrolling) { - [weakSelf scrollContinuousWithInterval:interval - after:delayAmount - labelAnimation:labelAnimation - gradientAnimation:gradientAnimation]; - } - } - }; - - - // Attach completion block - [labelAnimation setValue:@(YES) forKey:kMarqueeLabelAnimationCompletionBlock]; - - // Add animation - [self.subLabel.layer addAnimation:labelAnimation forKey:@"position"]; - - [CATransaction commit]; -} - -- (void)applyGradientMaskForFadeLength:(CGFloat)fadeLength animated:(BOOL)animated { - - // Remove any in-flight animations - [self.layer.mask removeAllAnimations]; - - // Check for zero-length fade - if (fadeLength <= 0.0f) { - [self removeGradientMask]; - return; - } - - // Configure gradient mask without implicit animations - [CATransaction begin]; - [CATransaction setDisableActions:YES]; - - CAGradientLayer *gradientMask = (CAGradientLayer *)self.layer.mask; - - // Set up colors - NSObject *transparent = (NSObject *)[[UIColor clearColor] CGColor]; - NSObject *opaque = (NSObject *)[[UIColor blackColor] CGColor]; - - if (!gradientMask) { - // Create CAGradientLayer if needed - gradientMask = [CAGradientLayer layer]; - gradientMask.shouldRasterize = YES; - gradientMask.rasterizationScale = [UIScreen mainScreen].scale; - gradientMask.startPoint = CGPointMake(0.0f, 0.5f); - gradientMask.endPoint = CGPointMake(1.0f, 0.5f); - } - - // Check if there is a mask-to-bounds size mismatch - if (!CGRectEqualToRect(gradientMask.bounds, self.bounds)) { - // Adjust stops based on fade length - CGFloat leftFadeStop = fadeLength/self.bounds.size.width; - CGFloat rightFadeStop = fadeLength/self.bounds.size.width; - gradientMask.locations = @[@(0.0f), @(leftFadeStop), @(1.0f - rightFadeStop), @(1.0f)]; - } - - gradientMask.bounds = self.layer.bounds; - gradientMask.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); - - // Set mask - self.layer.mask = gradientMask; - - // Determine colors for non-scrolling label (i.e. at home) - NSArray *adjustedColors; - BOOL trailingFadeNeeded = self.labelShouldScroll; - switch (self.marqueeType) { - case MLContinuousReverse: - case MLRightLeft: - case MLRight: - adjustedColors = @[(trailingFadeNeeded ? transparent : opaque), - opaque, - opaque, - opaque]; - break; - - default: - // MLContinuous - // MLLeftRight - adjustedColors = @[opaque, - opaque, - opaque, - (trailingFadeNeeded ? transparent : opaque)]; - break; - } - - // Check for IBDesignable -#if TARGET_INTERFACE_BUILDER - animated = NO; -#endif - - if (animated) { - // Finish transaction - [CATransaction commit]; - - // Create animation for color change - GradientSetupAnimation *colorAnimation = [GradientSetupAnimation animationWithKeyPath:@"colors"]; - colorAnimation.fromValue = gradientMask.colors; - colorAnimation.toValue = adjustedColors; - colorAnimation.duration = 0.25; - colorAnimation.removedOnCompletion = NO; - colorAnimation.delegate = self; - [gradientMask addAnimation:colorAnimation forKey:@"setupFade"]; - } else { - gradientMask.colors = adjustedColors; - [CATransaction commit]; - } -} - -- (void)removeGradientMask { - self.layer.mask = nil; -} - -- (CAKeyframeAnimation *)keyFrameAnimationForGradientFadeLength:(CGFloat)fadeLength - interval:(NSTimeInterval)interval - delay:(NSTimeInterval)delayAmount -{ - // Setup - NSArray *values = nil; - NSArray *keyTimes = nil; - NSTimeInterval totalDuration; - NSObject *transp = (NSObject *)[[UIColor clearColor] CGColor]; - NSObject *opaque = (NSObject *)[[UIColor blackColor] CGColor]; - - // Create new animation - CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"colors"]; - - // Get timing function - CAMediaTimingFunction *timingFunction = [self timingFunctionForAnimationOptions:self.animationCurve]; - - // Define keyTimes - switch (self.marqueeType) { - case MLLeftRight: - case MLRightLeft: - // Calculate total animation duration - totalDuration = 2.0 * (delayAmount + interval); - keyTimes = @[@(0.0), // 1) Initial gradient - @(delayAmount/totalDuration), // 2) Begin of LE fade-in, just as scroll away starts - @((delayAmount + 0.4)/totalDuration), // 3) End of LE fade in [LE fully faded] - @((delayAmount + interval - 0.4)/totalDuration), // 4) Begin of TE fade out, just before scroll away finishes - @((delayAmount + interval)/totalDuration), // 5) End of TE fade out [TE fade removed] - @((delayAmount + interval + delayAmount)/totalDuration), // 6) Begin of TE fade back in, just as scroll home starts - @((delayAmount + interval + delayAmount + 0.4)/totalDuration), // 7) End of TE fade back in [TE fully faded] - @((totalDuration - 0.4)/totalDuration), // 8) Begin of LE fade out, just before scroll home finishes - @(1.0)]; // 9) End of LE fade out, just as scroll home finishes - break; - - case MLLeft: - case MLRight: - // Calculate total animation duration - totalDuration = CGFLOAT_MAX; - keyTimes = @[@(0.0), // 1) Initial gradient - @(delayAmount/totalDuration), // 2) Begin of LE fade-in, just as scroll away starts - @((delayAmount + 0.4)/totalDuration), // 3) End of LE fade in [LE fully faded] - @((delayAmount + interval - 0.4)/totalDuration), // 4) Begin of TE fade out, just before scroll away finishes - @((delayAmount + interval)/totalDuration), // 5) End of TE fade out [TE fade removed] - @(1.0)]; - break; - case MLContinuousReverse: - default: - // Calculate total animation duration - totalDuration = delayAmount + interval; - - // Find when the lead label will be totally offscreen - CGFloat startFadeFraction = fabs((self.subLabel.bounds.size.width + self.leadingBuffer) / self.awayOffset); - // Find when the animation will hit that point - CGFloat startFadeTimeFraction = [timingFunction durationPercentageForPositionPercentage:startFadeFraction withDuration:totalDuration]; - NSTimeInterval startFadeTime = delayAmount + startFadeTimeFraction * interval; - - keyTimes = @[ - @(0.0), // Initial gradient - @(delayAmount/totalDuration), // Begin of fade in - @((delayAmount + 0.2)/totalDuration), // End of fade in, just as scroll away starts - @((startFadeTime)/totalDuration), // Begin of fade out, just before scroll home completes - @((startFadeTime + 0.1)/totalDuration), // End of fade out, as scroll home completes - @(1.0) // Buffer final value (used on continuous types) - ]; - break; - } - - // Define gradient values - // Get curent layer values - CAGradientLayer *currentMask = [[self maskLayer] presentationLayer]; - NSArray *currentValues = currentMask.colors; - - switch (self.marqueeType) { - case MLContinuousReverse: - values = @[ - (currentValues ? currentValues : @[transp, opaque, opaque, opaque]), // Initial gradient - @[transp, opaque, opaque, opaque], // Begin of fade in - @[transp, opaque, opaque, transp], // End of fade in, just as scroll away starts - @[transp, opaque, opaque, transp], // Begin of fade out, just before scroll home completes - @[transp, opaque, opaque, opaque], // End of fade out, as scroll home completes - @[transp, opaque, opaque, opaque] // Final "home" value - ]; - break; - - case MLRight: - values = @[ - (currentValues ? currentValues : @[transp, opaque, opaque, opaque]), // 1) - @[transp, opaque, opaque, opaque], // 2) - @[transp, opaque, opaque, transp], // 3) - @[transp, opaque, opaque, transp], // 4) - @[opaque, opaque, opaque, transp], // 5) - @[opaque, opaque, opaque, transp], // 6) - ]; - break; - - case MLRightLeft: - values = @[ - (currentValues ? currentValues : @[transp, opaque, opaque, opaque]), // 1) - @[transp, opaque, opaque, opaque], // 2) - @[transp, opaque, opaque, transp], // 3) - @[transp, opaque, opaque, transp], // 4) - @[opaque, opaque, opaque, transp], // 5) - @[opaque, opaque, opaque, transp], // 6) - @[transp, opaque, opaque, transp], // 7) - @[transp, opaque, opaque, transp], // 8) - @[transp, opaque, opaque, opaque] // 9) - ]; - break; - - case MLContinuous: - values = @[ - (currentValues ? currentValues : @[opaque, opaque, opaque, transp]), // Initial gradient - @[opaque, opaque, opaque, transp], // Begin of fade in - @[transp, opaque, opaque, transp], // End of fade in, just as scroll away starts - @[transp, opaque, opaque, transp], // Begin of fade out, just before scroll home completes - @[opaque, opaque, opaque, transp], // End of fade out, as scroll home completes - @[opaque, opaque, opaque, transp] // Final "home" value - ]; - break; - - case MLLeft: - values = @[ - (currentValues ? currentValues : @[opaque, opaque, opaque, transp]), // 1) - @[opaque, opaque, opaque, transp], // 2) - @[transp, opaque, opaque, transp], // 3) - @[transp, opaque, opaque, transp], // 4) - @[transp, opaque, opaque, opaque], // 5) - @[transp, opaque, opaque, opaque], // 6) - ]; - break; - - case MLLeftRight: - default: - values = @[ - (currentValues ? currentValues : @[opaque, opaque, opaque, transp]), // 1) - @[opaque, opaque, opaque, transp], // 2) - @[transp, opaque, opaque, transp], // 3) - @[transp, opaque, opaque, transp], // 4) - @[transp, opaque, opaque, opaque], // 5) - @[transp, opaque, opaque, opaque], // 6) - @[transp, opaque, opaque, transp], // 7) - @[transp, opaque, opaque, transp], // 8) - @[opaque, opaque, opaque, transp] // 9) - ]; - break; - } - - animation.values = values; - animation.keyTimes = keyTimes; - animation.timingFunctions = @[timingFunction, timingFunction, timingFunction, timingFunction]; - - return animation; -} - -- (CAKeyframeAnimation *)keyFrameAnimationForProperty:(NSString *)property - values:(NSArray *)values - interval:(NSTimeInterval)interval - delay:(NSTimeInterval)delayAmount -{ - // Create new animation - CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:property]; - - // Get timing function - CAMediaTimingFunction *timingFunction = [self timingFunctionForAnimationOptions:self.animationCurve]; - - // Calculate times based on marqueeType - NSTimeInterval totalDuration; - switch (self.marqueeType) { - case MLLeftRight: - case MLRightLeft: - NSAssert(values.count == 5, @"Incorrect number of values passed for MLLeftRight-type animation"); - totalDuration = 2.0 * (delayAmount + interval); - // Set up keyTimes - animation.keyTimes = @[@(0.0), // Initial location, home - @(delayAmount/totalDuration), // Initial delay, at home - @((delayAmount + interval)/totalDuration), // Animation to away - @((delayAmount + interval + delayAmount)/totalDuration), // Delay at away - @(1.0)]; // Animation to home - - animation.timingFunctions = @[timingFunction, - timingFunction, - timingFunction, - timingFunction]; - - break; - - case MLLeft: - case MLRight: - NSAssert(values.count == 4, @"Incorrect number of values passed for MLLeft-type animation"); - totalDuration = CGFLOAT_MAX; - // Set up keyTimes - animation.keyTimes = @[@(0.0), // Initial location, home - @(delayAmount/totalDuration), // Initial delay, at home - @((delayAmount + interval)/totalDuration), // Animation to away - @(1.0)]; // Animation to home - - animation.timingFunctions = @[timingFunction, - timingFunction, - timingFunction]; - - break; - - // MLContinuous - // MLContinuousReverse - default: - NSAssert(values.count == 3, @"Incorrect number of values passed for MLContinous-type animation"); - totalDuration = delayAmount + interval; - // Set up keyTimes - animation.keyTimes = @[@(0.0), // Initial location, home - @(delayAmount/totalDuration), // Initial delay, at home - @(1.0)]; // Animation to away - - animation.timingFunctions = @[timingFunction, - timingFunction]; - - break; - } - - // Set values - animation.values = values; - animation.delegate = self; - - return animation; -} - -- (CAMediaTimingFunction *)timingFunctionForAnimationOptions:(UIViewAnimationOptions)animationOptions { - NSString *timingFunction; - switch (animationOptions) { - case UIViewAnimationOptionCurveEaseIn: - timingFunction = kCAMediaTimingFunctionEaseIn; - break; - - case UIViewAnimationOptionCurveEaseInOut: - timingFunction = kCAMediaTimingFunctionEaseInEaseOut; - break; - - case UIViewAnimationOptionCurveEaseOut: - timingFunction = kCAMediaTimingFunctionEaseOut; - break; - - default: - timingFunction = kCAMediaTimingFunctionLinear; - break; - } - - return [CAMediaTimingFunction functionWithName:timingFunction]; -} - -- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { - if ([anim isMemberOfClass:[GradientSetupAnimation class]]) { - GradientSetupAnimation *setupFade = (GradientSetupAnimation *)anim; - NSArray *finalColors = setupFade.toValue; - if (finalColors) { - [(CAGradientLayer *)self.layer.mask setColors:finalColors]; - } - // Remove any/all setupFade animations regardless - [self.layer.mask removeAnimationForKey:@"setupFade"]; - } else { - if (self.scrollCompletionBlock) { - self.scrollCompletionBlock(flag); - } - } -} - -#pragma mark - Label Control - -- (void)restartLabel { - // Shutdown the label - [self shutdownLabel]; - // Restart scrolling if appropriate - if (self.labelShouldScroll && !self.tapToScroll && !self.holdScrolling) { - [self beginScroll]; - } -} - -- (void)resetLabel { - [self returnLabelToOriginImmediately]; - self.homeLabelFrame = CGRectNull; - self.awayOffset = 0.0f; -} - -- (void)shutdownLabel { - // Bring label to home location - [self returnLabelToOriginImmediately]; - // Apply gradient mask for home location - [self applyGradientMaskForFadeLength:self.fadeLength animated:false]; -} - --(void)pauseLabel -{ - // Only pause if label is not already paused, and already in a scrolling animation - if (!self.isPaused && self.awayFromHome) { - // Pause sublabel position animation - CFTimeInterval labelPauseTime = [self.subLabel.layer convertTime:CACurrentMediaTime() fromLayer:nil]; - self.subLabel.layer.speed = 0.0; - self.subLabel.layer.timeOffset = labelPauseTime; - // Pause gradient fade animation - CFTimeInterval gradientPauseTime = [self.layer.mask convertTime:CACurrentMediaTime() fromLayer:nil]; - self.layer.mask.speed = 0.0; - self.layer.mask.timeOffset = gradientPauseTime; - - self.isPaused = YES; - } -} - --(void)unpauseLabel -{ - if (self.isPaused) { - // Unpause sublabel position animation - CFTimeInterval labelPausedTime = self.subLabel.layer.timeOffset; - self.subLabel.layer.speed = 1.0; - self.subLabel.layer.timeOffset = 0.0; - self.subLabel.layer.beginTime = 0.0; - self.subLabel.layer.beginTime = [self.subLabel.layer convertTime:CACurrentMediaTime() fromLayer:nil] - labelPausedTime; - // Unpause gradient fade animation - CFTimeInterval gradientPauseTime = self.layer.mask.timeOffset; - self.layer.mask.speed = 1.0; - self.layer.mask.timeOffset = 0.0; - self.layer.mask.beginTime = 0.0; - self.layer.mask.beginTime = [self.layer.mask convertTime:CACurrentMediaTime() fromLayer:nil] - gradientPauseTime; - - self.isPaused = NO; - } -} - -- (void)labelWasTapped:(UITapGestureRecognizer *)recognizer { - if (self.labelShouldScroll && !self.awayFromHome) { - [self beginScrollWithDelay:NO]; - } -} - -- (void)triggerScrollStart { - if (self.labelShouldScroll && !self.awayFromHome) { - [self beginScroll]; - } -} - -- (void)labelWillBeginScroll { - // Default implementation does nothing - return; -} - -- (void)labelReturnedToHome:(BOOL)finished { - // Default implementation does nothing - return; -} - -#pragma mark - Modified UIView Methods/Getters/Setters - -- (void)setFrame:(CGRect)frame { - [super setFrame:frame]; - - // Check if device is running iOS 8.0.X - if(SYSTEM_VERSION_IS_8_0_X) { - // If so, force update because layoutSubviews is not called - [self updateSublabel]; - } -} - -- (void)setBounds:(CGRect)bounds { - [super setBounds:bounds]; - - // Check if device is running iOS 8.0.X - if(SYSTEM_VERSION_IS_8_0_X) { - // If so, force update because layoutSubviews is not called - [self updateSublabel]; - } - -} - -#pragma mark - Modified UILabel Methods/Getters/Setters - -#if __IPHONE_OS_VERSION_MAX_ALLOWED < 100000 && !(TARGET_OS_TV) -- (UIView *)viewForBaselineLayout { - // Use subLabel view for handling baseline layouts - return self.subLabel; -} -#endif - -- (UIView *)viewForLastBaselineLayout { - // Use subLabel view for handling baseline layouts - return self.subLabel; -} - -- (UIView *)viewForFirstBaselineLayout { - // Use subLabel view for handling baseline layouts - return self.subLabel; -} - -- (NSString *)text { - return self.subLabel.text; -} - -- (void)setText:(NSString *)text { - if ([text isEqualToString:self.subLabel.text]) { - return; - } - self.subLabel.text = text; - super.text = text; - [self updateSublabel]; -} - -- (NSAttributedString *)attributedText { - return self.subLabel.attributedText; -} - -- (void)setAttributedText:(NSAttributedString *)attributedText { - if ([attributedText isEqualToAttributedString:self.subLabel.attributedText]) { - return; - } - self.subLabel.attributedText = attributedText; - super.attributedText = attributedText; - [self updateSublabel]; -} - -- (UIFont *)font { - return self.subLabel.font; -} - -- (void)setFont:(UIFont *)font { - if ([font isEqual:self.subLabel.font]) { - return; - } - self.subLabel.font = font; - super.font = font; - [self updateSublabel]; -} - -- (UIColor *)textColor { - return self.subLabel.textColor; -} - -- (void)setTextColor:(UIColor *)textColor { - self.subLabel.textColor = textColor; - super.textColor = textColor; -} - -- (UIColor *)backgroundColor { - return self.subLabel.backgroundColor; -} - -- (void)setBackgroundColor:(UIColor *)backgroundColor { - self.subLabel.backgroundColor = backgroundColor; - super.backgroundColor = backgroundColor; -} - -- (UIColor *)shadowColor { - return self.subLabel.shadowColor; -} - -- (void)setShadowColor:(UIColor *)shadowColor { - self.subLabel.shadowColor = shadowColor; - super.shadowColor = shadowColor; -} - -- (CGSize)shadowOffset { - return self.subLabel.shadowOffset; -} - -- (void)setShadowOffset:(CGSize)shadowOffset { - self.subLabel.shadowOffset = shadowOffset; - super.shadowOffset = shadowOffset; -} - -- (UIColor *)highlightedTextColor { - return self.subLabel.highlightedTextColor; -} - -- (void)setHighlightedTextColor:(UIColor *)highlightedTextColor { - self.subLabel.highlightedTextColor = highlightedTextColor; - super.highlightedTextColor = highlightedTextColor; -} - -- (BOOL)isHighlighted { - return self.subLabel.isHighlighted; -} - -- (void)setHighlighted:(BOOL)highlighted { - self.subLabel.highlighted = highlighted; - super.highlighted = highlighted; -} - -- (BOOL)isEnabled { - return self.subLabel.isEnabled; -} - -- (void)setEnabled:(BOOL)enabled { - self.subLabel.enabled = enabled; - super.enabled = enabled; -} - -- (void)setNumberOfLines:(NSInteger)numberOfLines { - // By the nature of MarqueeLabel, this is 1 - [super setNumberOfLines:1]; -} - -- (void)setAdjustsFontSizeToFitWidth:(BOOL)adjustsFontSizeToFitWidth { - // By the nature of MarqueeLabel, this is NO - [super setAdjustsFontSizeToFitWidth:NO]; -} - -#if __IPHONE_OS_VERSION_MAX_ALLOWED < 70000 -- (void)setMinimumFontSize:(CGFloat)minimumFontSize { - [super setMinimumFontSize:0.0]; -} -#endif - -- (UIBaselineAdjustment)baselineAdjustment { - return self.subLabel.baselineAdjustment; -} - -- (void)setBaselineAdjustment:(UIBaselineAdjustment)baselineAdjustment { - self.subLabel.baselineAdjustment = baselineAdjustment; - super.baselineAdjustment = baselineAdjustment; -} - -- (UIColor *)tintColor { - return self.subLabel.tintColor; -} - -- (void)setTintColor:(UIColor *)tintColor { - self.subLabel.tintColor = tintColor; - super.tintColor = tintColor; -} - -- (void)tintColorDidChange { - [super tintColorDidChange]; - [self.subLabel tintColorDidChange]; -} - -- (CGSize)intrinsicContentSize { - CGSize contentSize = self.subLabel.intrinsicContentSize; - contentSize.width += self.leadingBuffer; - return contentSize; -} - -#if __IPHONE_OS_VERSION_MAX_ALLOWED < 70000 -- (void)setAdjustsLetterSpacingToFitWidth:(BOOL)adjustsLetterSpacingToFitWidth { - // By the nature of MarqueeLabel, this is NO - [super setAdjustsLetterSpacingToFitWidth:NO]; -} -#endif - -- (void)setMinimumScaleFactor:(CGFloat)minimumScaleFactor { - [super setMinimumScaleFactor:0.0f]; -} - -- (UIViewContentMode)contentMode { - return self.subLabel.contentMode; -} - -- (void)setContentMode:(UIViewContentMode)contentMode { - super.contentMode = contentMode; - self.subLabel.contentMode = contentMode; -} - -- (void)setIsAccessibilityElement:(BOOL)isAccessibilityElement { - [super setIsAccessibilityElement:isAccessibilityElement]; - self.subLabel.isAccessibilityElement = isAccessibilityElement; -} - -#pragma mark - Custom Getters and Setters - -- (void)setRate:(CGFloat)rate { - if (_rate == rate) { - return; - } - - _scrollDuration = 0.0f; - _rate = rate; - [self updateSublabel]; -} - -- (void)setScrollDuration:(CGFloat)lengthOfScroll { - if (_scrollDuration == lengthOfScroll) { - return; - } - - _rate = 0.0f; - _scrollDuration = lengthOfScroll; - [self updateSublabel]; -} - -- (void)setAnimationCurve:(UIViewAnimationOptions)animationCurve { - if (_animationCurve == animationCurve) { - return; - } - - NSUInteger allowableOptions = UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionCurveLinear; - if ((allowableOptions & animationCurve) == animationCurve) { - _animationCurve = animationCurve; - } -} - -- (void)setLeadingBuffer:(CGFloat)leadingBuffer { - if (_leadingBuffer == leadingBuffer) { - return; - } - - // Do not allow negative values - _leadingBuffer = fabs(leadingBuffer); - [self updateSublabel]; -} - -- (void)setTrailingBuffer:(CGFloat)trailingBuffer { - if (_trailingBuffer == trailingBuffer) { - return; - } - - // Do not allow negative values - _trailingBuffer = fabs(trailingBuffer); - [self updateSublabel]; -} - -- (void)setContinuousMarqueeExtraBuffer:(CGFloat)continuousMarqueeExtraBuffer { - [self setTrailingBuffer:continuousMarqueeExtraBuffer]; -} - -- (CGFloat)continuousMarqueeExtraBuffer { - return self.trailingBuffer; -} - -- (void)setFadeLength:(CGFloat)fadeLength { - if (_fadeLength == fadeLength) { - return; - } - - _fadeLength = fadeLength; - - [self updateSublabel]; -} - -- (void)setTapToScroll:(BOOL)tapToScroll { - if (_tapToScroll == tapToScroll) { - return; - } - - _tapToScroll = tapToScroll; - - if (_tapToScroll) { - UITapGestureRecognizer *newTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelWasTapped:)]; - [self addGestureRecognizer:newTapRecognizer]; - self.tapRecognizer = newTapRecognizer; - self.userInteractionEnabled = YES; - } else { - [self removeGestureRecognizer:self.tapRecognizer]; - self.tapRecognizer = nil; - self.userInteractionEnabled = NO; - } -} - -- (void)setMarqueeType:(MarqueeType)marqueeType { - if (marqueeType == _marqueeType) { - return; - } - - _marqueeType = marqueeType; - - [self updateSublabel]; -} - -- (void)setLabelize:(BOOL)labelize { - if (_labelize == labelize) { - return; - } - - _labelize = labelize; - - [self updateSublabelAndBeginScroll:YES]; -} - -- (void)setHoldScrolling:(BOOL)holdScrolling { - if (_holdScrolling == holdScrolling) { - return; - } - - _holdScrolling = holdScrolling; - - if (!holdScrolling && !(self.awayFromHome || self.labelize || self.tapToScroll) && self.labelShouldScroll) { - [self beginScroll]; - } -} - -- (BOOL)awayFromHome { - CALayer *presentationLayer = self.subLabel.layer.presentationLayer; - if (!presentationLayer) { - return NO; - } - return !(presentationLayer.position.x == self.homeLabelFrame.origin.x); -} - -#pragma mark - Support - -- (NSArray *)gradientColors { - if (!_gradientColors) { - NSObject *transparent = (NSObject *)[[UIColor clearColor] CGColor]; - NSObject *opaque = (NSObject *)[[UIColor blackColor] CGColor]; - _gradientColors = [NSArray arrayWithObjects: transparent, opaque, opaque, transparent, nil]; - } - return _gradientColors; -} - -#pragma mark - - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -@end - - - -#pragma mark - Helpers - -CGPoint MLOffsetCGPoint(CGPoint point, CGFloat offset) { - return CGPointMake(point.x + offset, point.y); -} - -@implementation GradientSetupAnimation - -@end - -@implementation UIView (MarqueeLabelHelpers) -// Thanks to Phil M -// http://stackoverflow.com/questions/1340434/get-to-uiviewcontroller-from-uiview-on-iphone - -- (id)firstAvailableViewController -{ - // convenience function for casting and to "mask" the recursive function - return [self traverseResponderChainForFirstViewController]; -} - -- (id)traverseResponderChainForFirstViewController -{ - id nextResponder = [self nextResponder]; - if ([nextResponder isKindOfClass:[UIViewController class]]) { - return nextResponder; - } else if ([nextResponder isKindOfClass:[UIView class]]) { - return [nextResponder traverseResponderChainForFirstViewController]; - } else { - return nil; - } -} - -@end - -@implementation CAMediaTimingFunction (MarqueeLabelHelpers) - -- (CGFloat)durationPercentageForPositionPercentage:(CGFloat)positionPercentage withDuration:(NSTimeInterval)duration -{ - // Finds the animation duration percentage that corresponds with the given animation "position" percentage. - // Utilizes Newton's Method to solve for the parametric Bezier curve that is used by CAMediaAnimation. - - NSArray *controlPoints = [self controlPoints]; - CGFloat epsilon = 1.0f / (100.0f * duration); - - // Find the t value that gives the position percentage we want - CGFloat t_found = [self solveTForY:positionPercentage - withEpsilon:epsilon - controlPoints:controlPoints]; - - // With that t, find the corresponding animation percentage - CGFloat durationPercentage = [self XforCurveAt:t_found withControlPoints:controlPoints]; - - return durationPercentage; -} - -- (CGFloat)solveTForY:(CGFloat)y_0 withEpsilon:(CGFloat)epsilon controlPoints:(NSArray *)controlPoints -{ - // Use Newton's Method: http://en.wikipedia.org/wiki/Newton's_method - // For first guess, use t = y (i.e. if curve were linear) - CGFloat t0 = y_0; - CGFloat t1 = y_0; - CGFloat f0, df0; - - for (int i = 0; i < 15; i++) { - // Base this iteration of t1 calculated from last iteration - t0 = t1; - // Calculate f(t0) - f0 = [self YforCurveAt:t0 withControlPoints:controlPoints] - y_0; - // Check if this is close (enough) - if (fabs(f0) < epsilon) { - // Done! - return t0; - } - // Else continue Newton's Method - df0 = [self derivativeYValueForCurveAt:t0 withControlPoints:controlPoints]; - // Check if derivative is small or zero ( http://en.wikipedia.org/wiki/Newton's_method#Failure_analysis ) - if (fabs(df0) < 1e-6) { - NSLog(@"MarqueeLabel: Newton's Method failure, small/zero derivative!"); - break; - } - // Else recalculate t1 - t1 = t0 - f0/df0; - } - - NSLog(@"MarqueeLabel: Failed to find t for Y input!"); - return t0; -} - -- (CGFloat)YforCurveAt:(CGFloat)t withControlPoints:(NSArray *)controlPoints -{ - CGPoint P0 = [controlPoints[0] CGPointValue]; - CGPoint P1 = [controlPoints[1] CGPointValue]; - CGPoint P2 = [controlPoints[2] CGPointValue]; - CGPoint P3 = [controlPoints[3] CGPointValue]; - - // Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves - return powf((1 - t),3) * P0.y + - 3.0f * powf(1 - t, 2) * t * P1.y + - 3.0f * (1 - t) * powf(t, 2) * P2.y + - powf(t, 3) * P3.y; - -} - -- (CGFloat)XforCurveAt:(CGFloat)t withControlPoints:(NSArray *)controlPoints -{ - CGPoint P0 = [controlPoints[0] CGPointValue]; - CGPoint P1 = [controlPoints[1] CGPointValue]; - CGPoint P2 = [controlPoints[2] CGPointValue]; - CGPoint P3 = [controlPoints[3] CGPointValue]; - - // Per http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves - return powf((1 - t),3) * P0.x + - 3.0f * powf(1 - t, 2) * t * P1.x + - 3.0f * (1 - t) * powf(t, 2) * P2.x + - powf(t, 3) * P3.x; - -} - -- (CGFloat)derivativeYValueForCurveAt:(CGFloat)t withControlPoints:(NSArray *)controlPoints -{ - CGPoint P0 = [controlPoints[0] CGPointValue]; - CGPoint P1 = [controlPoints[1] CGPointValue]; - CGPoint P2 = [controlPoints[2] CGPointValue]; - CGPoint P3 = [controlPoints[3] CGPointValue]; - - return powf(t, 2) * (-3.0f * P0.y - 9.0f * P1.y - 9.0f * P2.y + 3.0f * P3.y) + - t * (6.0f * P0.y + 6.0f * P2.y) + - (-3.0f * P0.y + 3.0f * P1.y); -} - -- (NSArray *)controlPoints -{ - float point[2]; - NSMutableArray *pointArray = [NSMutableArray array]; - for (int i = 0; i <= 3; i++) { - [self getControlPointAtIndex:i values:point]; - [pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(point[0], point[1])]]; - } - - return [NSArray arrayWithArray:pointArray]; -} - -@end diff --git a/Pods/NapySlider/NapySlider/NapySlider.swift b/Pods/NapySlider/NapySlider/NapySlider.swift index ca51d16..ca93f9d 100644 --- a/Pods/NapySlider/NapySlider/NapySlider.swift +++ b/Pods/NapySlider/NapySlider/NapySlider.swift @@ -31,42 +31,44 @@ open class NapySlider: UIControl { } // public variables - var titleHeight: CGFloat = 30 - var sliderWidth: CGFloat = 20 - var handleHeight: CGFloat = 20 - var handleWidth: CGFloat = 50 + @IBInspectable public var titleHeight: CGFloat = 30 + @IBInspectable public var sliderWidth: CGFloat = 20 + @IBInspectable public var handleHeight: CGFloat = 20 + @IBInspectable public var handleWidth: CGFloat = 50 + @IBInspectable public var sliderPaddingTop:CGFloat = 25 + @IBInspectable public var sliderPaddingBottom:CGFloat = 20 // public inspectable variables - @IBInspectable var title: String = "Hello" { + @IBInspectable public var title: String = "Hello" { didSet { titleLabel.text = title } } - @IBInspectable var min: Double = 0 { + @IBInspectable public var min: Double = 0 { didSet { minLabel.text = textForPosition(min) } } - @IBInspectable var max: Double = 10 { + @IBInspectable public var max: Double = 10 { didSet { maxLabel.text = textForPosition(max) } } - @IBInspectable var step: Double = 1 + @IBInspectable public var step: Double = 1 // colors - @IBInspectable var handleColor: UIColor = UIColor.gray - @IBInspectable var mainBackgroundColor: UIColor = UIColor.groupTableViewBackground - @IBInspectable var titleBackgroundColor: UIColor = UIColor.lightGray - @IBInspectable var sliderUnselectedColor: UIColor = UIColor.lightGray + @IBInspectable public var handleColor: UIColor = UIColor.gray + @IBInspectable public var mainBackgroundColor: UIColor = UIColor.groupTableViewBackground + @IBInspectable public var titleBackgroundColor: UIColor = UIColor.lightGray + @IBInspectable public var sliderUnselectedColor: UIColor = UIColor.lightGray /** the position of the handle. The handle moves animated when setting the variable */ - var handlePosition:Double { + open var handlePosition:Double { set (newHandlePosition) { moveHandleToPosition(newHandlePosition, animated: true) } @@ -89,7 +91,7 @@ open class NapySlider: UIControl { } } - var disabled:Bool = false { + open var disabled:Bool = false { didSet { sliderBackgroundView.alpha = disabled ? 0.4 : 1.0 self.isUserInteractionEnabled = !disabled @@ -132,7 +134,7 @@ open class NapySlider: UIControl { self.setup() } - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) self.setup() @@ -184,9 +186,6 @@ open class NapySlider: UIControl { open override func layoutSubviews() { super.layoutSubviews() - let sliderPaddingTop:CGFloat = 25 - let sliderPaddingBottom:CGFloat = 20 - backgroundView.frame = CGRect(x: 0, y: titleHeight, width: frame.size.width, height: frame.size.height - titleHeight) backgroundView.backgroundColor = mainBackgroundColor @@ -196,7 +195,7 @@ open class NapySlider: UIControl { titleLabel.frame = CGRect(x: 0, y: 0, width: titleBackgroundView.frame.width, height: titleBackgroundView.frame.height) titleLabel.text = title titleLabel.textColor = handleColor - titleLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightSemibold) + titleLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.semibold) titleLabel.textAlignment = NSTextAlignment.center sliderBackgroundView.frame = CGRect(x: backgroundView.frame.width/2 - sliderWidth/2, y: sliderPaddingTop, width: sliderWidth, height: backgroundView.frame.height - (sliderPaddingTop + sliderPaddingBottom)) @@ -211,30 +210,33 @@ open class NapySlider: UIControl { sliderFillView.frame = CGRect(x: 0, y: handleView.frame.origin.y + handleHeight, width: sliderBackgroundView.frame.width, height: sliderBackgroundView.frame.height-handleView.frame.origin.y - handleHeight) sliderFillView.backgroundColor = tintColor + /* handleLabel.frame = CGRect(x: 0, y: 0, width: handleWidth, height: handleHeight) handleLabel.text = "" handleLabel.textAlignment = NSTextAlignment.center handleLabel.textColor = UIColor.white - handleLabel.font = UIFont.systemFont(ofSize: 11, weight: UIFontWeightBold) + handleLabel.font = UIFont.systemFont(ofSize: 11, weight: UIFont.Weight.bold) handleLabel.backgroundColor = UIColor.clear - - minLabel.frame = CGRect(x: 0, y: backgroundView.frame.height-20, width: backgroundView.frame.width, height: 20) + handleLabel.adjustsFontSizeToFitWidth = true + */ + + minLabel.frame = CGRect(x: 0, y: backgroundView.frame.height-sliderPaddingBottom, width: backgroundView.frame.width, height: sliderPaddingBottom) minLabel.text = textForPosition(min) minLabel.textAlignment = NSTextAlignment.center - minLabel.font = UIFont.systemFont(ofSize: 11, weight: UIFontWeightRegular) + minLabel.font = UIFont.systemFont(ofSize: 11, weight: UIFont.Weight.regular) minLabel.textColor = handleColor - maxLabel.frame = CGRect(x: 0, y: 5, width: backgroundView.frame.width, height: 20) + maxLabel.frame = CGRect(x: 0, y: 0, width: backgroundView.frame.width, height: sliderPaddingTop) maxLabel.text = textForPosition(max) maxLabel.textAlignment = NSTextAlignment.center - maxLabel.font = UIFont.systemFont(ofSize: 11, weight: UIFontWeightRegular) + maxLabel.font = UIFont.systemFont(ofSize: 11, weight: UIFont.Weight.regular) maxLabel.textColor = handleColor currentPosLabel.frame = CGRect(x: handleView.frame.width, y: handleView.frame.origin.y + handleHeight*0.5/2, width: handleWidth, height: handleHeight * 1.5) currentPosLabel.text = "" currentPosLabel.textAlignment = NSTextAlignment.center currentPosLabel.textColor = UIColor.white - handleLabel.font = UIFont.systemFont(ofSize: 13, weight: UIFontWeightBold) + handleLabel.font = UIFont.systemFont(ofSize: 13, weight: UIFont.Weight.bold) currentPosLabel.backgroundColor = tintColor currentPosLabel.alpha = 0.0 @@ -292,13 +294,17 @@ open class NapySlider: UIControl { handleView.frame.origin.y = CGFloat(newY) sliderFillView.frame = CGRect(x: 0 , y: CGFloat(newY) + handleHeight, width: sliderBackgroundView.frame.width, height: sliderBackgroundView.frame.height-handleView.frame.origin.y - handleHeight) - currentPosLabel.frame = CGRect(x: handleView.frame.width, y: handleView.frame.origin.y + handleHeight*0.5/2, width: currentPosLabel.frame.width, height: currentPosLabel.frame.height) - let newText = textForPosition(handlePosition) if handleLabel.text != newText { handleLabel.text = newText currentPosLabel.text = newText } + + currentPosLabel.sizeToFit() + + currentPosLabel.frame = CGRect(x: handleView.frame.width + 10, y: handleView.frame.origin.y + handleHeight*0.5/2, width: currentPosLabel.frame.width + 16, height: currentPosLabel.frame.height + 16) + + currentPosTriangle.frame = CGRect(x: -10, y: currentPosLabel.frame.height / 2.0 - 10, width: 20, height: 20) } fileprivate func moveHandleToPosition(_ position:Double, animated:Bool = false) { @@ -313,16 +319,14 @@ open class NapySlider: UIControl { let newY = CGFloat(minPosition - positionFromMin * stepheight) - if animated { - UIView.animate(withDuration: 0.3, animations: { - self.handleView.frame.origin.y = newY - self.handleHeight/2 - self.sliderFillView.frame = CGRect(x: 0 , y: CGFloat(newY) + self.handleHeight/2, width: self.sliderBackgroundView.frame.width, height: self.sliderBackgroundView.frame.height - self.handleView.frame.origin.y - self.handleHeight) - self.currentPosLabel.frame = CGRect(x: self.handleView.frame.width, y: self.handleView.frame.origin.y + self.handleHeight*0.5/2, width: self.currentPosLabel.frame.width, height: self.currentPosLabel.frame.height) - }) - } else { + let changes = { + self.currentPosLabel.sizeToFit() + self.handleView.frame.origin.y = newY - self.handleHeight/2 - self.sliderFillView.frame.origin.y = CGFloat(newY) + self.handleHeight - currentPosLabel.frame = CGRect(x: handleView.frame.width, y: handleView.frame.origin.y + handleHeight*0.5/2, width: currentPosLabel.frame.width, height: currentPosLabel.frame.height) + self.sliderFillView.frame = CGRect(x: 0 , y: CGFloat(newY) + self.handleHeight/2, width: self.sliderBackgroundView.frame.width, height: self.sliderBackgroundView.frame.height - self.handleView.frame.origin.y - self.handleHeight) + self.currentPosLabel.frame = CGRect(x: self.handleView.frame.width + 10, y: self.handleView.frame.origin.y + self.handleHeight*0.5/2, width: self.currentPosLabel.frame.width + 16, height: self.currentPosLabel.frame.height + 16) + + self.currentPosTriangle.frame = CGRect(x: -10, y: self.currentPosLabel.frame.height / 2.0 - 10, width: 20, height: 20) } let newText = textForPosition(position) @@ -330,6 +334,14 @@ open class NapySlider: UIControl { handleLabel.text = newText currentPosLabel.text = newText } + + if animated { + UIView.animate(withDuration: 0.3, animations: changes) + } else { + changes() + } + + self.sendActions(for: .valueChanged) } fileprivate func textForPosition(_ position:Double) -> String { diff --git a/Pods/NapySlider/README.md b/Pods/NapySlider/README.md index ebfe9c4..126d984 100644 --- a/Pods/NapySlider/README.md +++ b/Pods/NapySlider/README.md @@ -1,8 +1,6 @@ # NapySlider A vertical slider UIControl element written in swift -[![Build Status](https://travis-ci.org/seeppp/NapySlider.svg?branch=master)](https://travis-ci.org/seeppp/NapySlider) - ![demo](/exampleImages/napysliderdemo.gif) ## Howto diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj index c1ce639..ff2c423 100644 --- a/Pods/Pods.xcodeproj/project.pbxproj +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -7,67 +7,66 @@ objects = { /* Begin PBXBuildFile section */ - 0198CA25F234B7889463C862AE27F888 /* SpringInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FB47A2FBDD8DAAA5569426552F5C4B /* SpringInterpolation.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 04C65DA88F744676EC9665E2B406E86F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C0093CC370B28EC079B3E16F69473B4 /* Foundation.framework */; }; - 0EC567AB0CFA098BEC23D7B29514ACB0 /* MarqueeLabel-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F50AD6D3FF4576CD0AF6EEE58B4EC608 /* MarqueeLabel-dummy.m */; }; - 137BA0D4787A3F404C1C95841153CDA5 /* NapySlider-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 10764428BEEC44CF067CC511AF86283E /* NapySlider-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1674B2F944517C6E6E3EC22E59734D83 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D60565EB9DCB2758274A8A02FF2A0320 /* Accelerate.framework */; }; - 17D10ADFC7CFDC54B366F5864B3419A7 /* bass.h in Headers */ = {isa = PBXBuildFile; fileRef = 4786BAC1DA89E012B0E2CEB92968B684 /* bass.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2E6A5DB2EEB0163621E9F1B4C5AA3A5B /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 86E6F0FE7E08AFE6BD95000C8D795582 /* SystemConfiguration.framework */; }; - 3521D456B138B72A36202F946977A43F /* Interpolate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90B959B5840715C6FB6917FC16D8F58 /* Interpolate.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 380FBEAFB6C5E2A468B8F8E1ABF6E47F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C0093CC370B28EC079B3E16F69473B4 /* Foundation.framework */; }; - 40AB371EC00736015C6526F9FADA7695 /* MarqueeLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = F1404CB31839B4066F9B2DE1424821BB /* MarqueeLabel.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 46DF40AB8F2C9EE4C8F87DEAEA71463D /* MarqueeLabel-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 87B7410AA702A125875A21A472179101 /* MarqueeLabel-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 505378D3562F35935EBA2E957C0B15C7 /* ObjectiveBASS.m in Sources */ = {isa = PBXBuildFile; fileRef = BF22209231A18D8F188E75C2F190E2A0 /* ObjectiveBASS.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 50A5E3272E920B2E569BCEA6D4298C60 /* Pods-AGAudioPlayer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 307640F886D98B5FB530F19B9F1054A6 /* Pods-AGAudioPlayer-dummy.m */; }; - 50B0AAD9FB5E4C77E36623A31B927B6D /* Interpolate-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF306EAC475D248C1E97159A904D82D /* Interpolate-dummy.m */; }; - 5AA4289D7E9D275A1EC619865F4FCFAA /* Interpolate.h in Headers */ = {isa = PBXBuildFile; fileRef = 031A192D2BCE6031289DF14271500286 /* Interpolate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 621D7DE60B15A0D70C797FBF59499569 /* BASSGaplessAudioPlayer-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 431B9AEEBEF6525AF7F0BE79DAF4EEAC /* BASSGaplessAudioPlayer-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6D67F7261BF63AFB0936BBBE3C6D8B86 /* ObjectiveBASS.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B2FFAA4F174460C5E52E658EB0DC5EC /* ObjectiveBASS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 769ACB66C78813C45EEEA361954F2FD9 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C564755FA1097CCB1C6F0C0B0249B770 /* QuartzCore.framework */; }; - 776296316A3C8280B40496CB97B5C859 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C0093CC370B28EC079B3E16F69473B4 /* Foundation.framework */; }; - 778A155DD461946668FB16CE3D568D5E /* bass_fx.h in Headers */ = {isa = PBXBuildFile; fileRef = B28773E3B3C02BDAEFF9F7C6A13234CF /* bass_fx.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8FE0C33F0EAF94EAE7360DDC8DB718FE /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73BF4D51B00BAD619B8A51DE57B82293 /* AudioToolbox.framework */; }; - 9B530806BF8728898EE2BA4D763F8898 /* Interpolate-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A56DB7536E6DB8BED825692E020E9852 /* Interpolate-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C420C54006E88A2674418F5A5F83E23 /* NapySlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274228006E3F8CF58C4C723E7654B305 /* NapySlider.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 9C67CFBBBEE08E50BA939362A7769E8B /* bassmix.h in Headers */ = {isa = PBXBuildFile; fileRef = B1B8935D5C98F0C9FE93EE7F00A20701 /* bassmix.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A126DF6F537828B8E3AB6AD732E74369 /* BASSGaplessAudioPlayer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 540CD64EBFCF9B8928139B99FCDE7C51 /* BASSGaplessAudioPlayer-dummy.m */; }; - A821FDE252B0728C61E1B5AFBE1E42F2 /* Interpolatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A8955F1AB5F47DBC1524111B92A880B /* Interpolatable.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - AB0CE01ED1B3A358D14B2B8133C66FB7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C0093CC370B28EC079B3E16F69473B4 /* Foundation.framework */; }; - BEBE27F2D0DDF50913A65C819BF5FD0A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7369132A6E0B80E7F3259CDC5EF10277 /* UIKit.framework */; }; - C881683BD376A842DBBC19FF2D2BCF17 /* MarqueeLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = FC3BC8D64B1FF838633F1BFB1A4D2598 /* MarqueeLabel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D3C29D5F100517A9C081C97C2FAB1F02 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53DDEACD638180ABAF3D93015F3A6234 /* CFNetwork.framework */; }; - D94CA838EBF30A78E2C6FCB1D4817D74 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C0093CC370B28EC079B3E16F69473B4 /* Foundation.framework */; }; - DC909A9574EFE68A74739AEE9CC37C0C /* BasicInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F88747EA13634931FA51285F2700B3A /* BasicInterpolation.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - E719B6F7CAC97346BA0AE8E4E5B500E5 /* NapySlider-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 880F1F3DD6416E47D95FCFF808332C9E /* NapySlider-dummy.m */; }; - EDA1087BB8E333A30B30B2A0B99032F3 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C564755FA1097CCB1C6F0C0B0249B770 /* QuartzCore.framework */; }; - F72B35E9A5B0940F5E5A2EF245511D2A /* Pods-AGAudioPlayer-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = AAF752C63D4E09DBD560612EED7FDD77 /* Pods-AGAudioPlayer-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FFC94BB458FADE168ADCC826BA75DCE7 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 458253104CE91517F7B9ADE0EB532420 /* AVFoundation.framework */; }; + 0FE2278C2EB5C497302110A87BDCE16C /* Interpolate.h in Headers */ = {isa = PBXBuildFile; fileRef = 03E12B1D7C2DA8E97F2AEC9DBBA4BB16 /* Interpolate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 15F020BD77E6767B2E1F06FB110CEFC8 /* ObjectiveBASS.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6B50DC4232E11243786EF5C5A9F6BC /* ObjectiveBASS.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 20DC980C3816419715B74E552C137410 /* Interpolate-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 88D2A3E3E19BEF49E44621413D499D73 /* Interpolate-dummy.m */; }; + 26A0AE07E76AD8DE9ED97B151B827617 /* BasicInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE051EA6D5A288F4ACAC618BC0015B6 /* BasicInterpolation.swift */; }; + 30110AED9A917C9623959A5A33BEC6D2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7101FF48687E763E7A4FF2220F620B7 /* Foundation.framework */; }; + 310C7A5DFC8B7E026C14D2B2F211E98B /* Interpolate-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B39AD3BD156F512505171E9161471454 /* Interpolate-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3249E6DD0EC7BC3D28A17B2788E69360 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D06F44B6F1D454EB08F649853397BA2 /* SystemConfiguration.framework */; }; + 34BDFAD1754BC0D4F83B669C43E9442E /* NapySlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD4B5CB75169B7D5D2801BFE50E8303 /* NapySlider.swift */; }; + 37C514D75917BD2FBC6789A6ED50E780 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7101FF48687E763E7A4FF2220F620B7 /* Foundation.framework */; }; + 48C84AA27B8C55FFBD1BF37080637F75 /* BASSGaplessAudioPlayer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 034F1B8838A5E28AB2CDF09760095EC3 /* BASSGaplessAudioPlayer-dummy.m */; }; + 4DD3BF565D8F923F1BFE664F3896F6CD /* Pods-AGAudioPlayer-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = AAF752C63D4E09DBD560612EED7FDD77 /* Pods-AGAudioPlayer-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5788009C2C2DB44FB0FF45A3DB7AB6C6 /* Interpolatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963E1ECAAD3093CD9A7A193BD5C439E9 /* Interpolatable.swift */; }; + 5E5CD62A44974AA675EC22DCE3DD3B8B /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCBF85811ABE2D31327A21FC025BC4F5 /* Accelerate.framework */; }; + 665724D8DCC2E0CFEEF037843846D54E /* NapySlider-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E16A3A1BABEC0E6FAD525B3779B69C22 /* NapySlider-dummy.m */; }; + 689C5EDE87027BC85DAE9DEE0681C540 /* ObjectiveBASS.h in Headers */ = {isa = PBXBuildFile; fileRef = 449808036D39DCE9C36549B56F4B416E /* ObjectiveBASS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 693E153BB9ADF58542E30A14E0503157 /* BASSGaplessAudioPlayer-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C4C3228FBDAD0409877F32075F75250 /* BASSGaplessAudioPlayer-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 70302383A232F13569F5C63A5F2A53A9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7101FF48687E763E7A4FF2220F620B7 /* Foundation.framework */; }; + 74EE97E4DED44D7BDF9E87454590D2DD /* Pods-AGAudioPlayer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 307640F886D98B5FB530F19B9F1054A6 /* Pods-AGAudioPlayer-dummy.m */; }; + 82C0B8158E9D5764869040A461043694 /* bass.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B873A5F2C2EFC9169898165B53C54F2 /* bass.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 90E03814819D335B5F0784F62C5AE92B /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65E4EB4434BC04DFA34D2B815B4DB15D /* CFNetwork.framework */; }; + A09FD26C0D41B65DEB1011AAB095C631 /* NapySlider-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 82D85BAA8D425B9474900DC28E87F93E /* NapySlider-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A393DCAFE058E0917CDD5BF0442E26AC /* bass_fx.h in Headers */ = {isa = PBXBuildFile; fileRef = 99973F10E433E52E6CB9C03F0AE81E10 /* bass_fx.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A7870A395B3E7F1C70327A75ABA4796F /* bassmix.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AD49DF7F7A8018A405794057F45B02E /* bassmix.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ADE8E38AE2FC314562F857E3D97467C4 /* MarqueeLabel-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 02C73980B515157CA57547B0E246BC0D /* MarqueeLabel-dummy.m */; }; + AEABDD2270E3533912D4C9A8D36C6436 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEFE5867B2DAD43D6916B66FC48FFC70 /* QuartzCore.framework */; }; + BA87DAC94CCFD94B2C960C7F3C1639FA /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8115BD556FB1A3CBE4E55E26790EE72B /* AudioToolbox.framework */; }; + BD503BE4798FC30D23AC747146D39FE2 /* MarqueeLabel-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FB339A4A552294BA385A565BCCB9D7A /* MarqueeLabel-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C8BB2EAEB3F03D521DC374327ADD7FE7 /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BAC08A79C64949D5E88F42C0A29EC /* MarqueeLabel.swift */; }; + CA6B7B11EAE51C6E3453876018130527 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7101FF48687E763E7A4FF2220F620B7 /* Foundation.framework */; }; + CADD2A1613A4CBD5023DD8ECD06DFBCC /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEFE5867B2DAD43D6916B66FC48FFC70 /* QuartzCore.framework */; }; + CFE2C3DE4CCDAF6879E25224EE092955 /* SpringInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05FBC77B1E082351F79B38317AD7B1EB /* SpringInterpolation.swift */; }; + E2BAAB41FAF2ABB257F90E7F6F3BA4DF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7101FF48687E763E7A4FF2220F620B7 /* Foundation.framework */; }; + E771CDF7837319A49468CC35D18D8434 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA8497B44E9CF89DEAFF36CEE598247E /* UIKit.framework */; }; + EEBFA31D279AC93F0B9FDCC1B18EB48C /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47574FDB25394C63FFDBF8CBA3E34542 /* AVFoundation.framework */; }; + EF865541300D89F9D52951642F6309B8 /* Interpolate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AD13B92C34D9A459335780C4556B21 /* Interpolate.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 1F08096FDF3B347E4DA9541CDA53EDD5 /* PBXContainerItemProxy */ = { + 06734A1B4450AE9F3EBDB22DDE45FA76 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = C23DB88E45B0ED14F0C8827BE9C46C95; remoteInfo = MarqueeLabel; }; - 38643B974A16547DA1E86A74C7BB1F7B /* PBXContainerItemProxy */ = { + 1285A8B5F12BDF35DBB07D9239756E5F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 03AE74D07594E1CB394E8D6D1ACA8180; remoteInfo = NapySlider; }; - 77AF471CF468A736072DE9D98B621E0C /* PBXContainerItemProxy */ = { + 9587A777AA42611DC380EF488132EE78 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 6C7CE3CDC16FE41E5088964C355F522A; remoteInfo = Interpolate; }; - C814F95853A36C1EC026E2D2F9D53466 /* PBXContainerItemProxy */ = { + D010C847F1FFBFAC74FB4347F136A64D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; @@ -77,341 +76,320 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 031A192D2BCE6031289DF14271500286 /* Interpolate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Interpolate.h; path = Interpolate/Interpolate.h; sourceTree = ""; }; - 059DFD3E8A04B57A637E82149B6CB834 /* NapySlider-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "NapySlider-Info.plist"; sourceTree = ""; }; - 0F88747EA13634931FA51285F2700B3A /* BasicInterpolation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BasicInterpolation.swift; path = Interpolate/BasicInterpolation.swift; sourceTree = ""; }; - 10764428BEEC44CF067CC511AF86283E /* NapySlider-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "NapySlider-umbrella.h"; sourceTree = ""; }; + 02C73980B515157CA57547B0E246BC0D /* MarqueeLabel-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "MarqueeLabel-dummy.m"; sourceTree = ""; }; + 034F1B8838A5E28AB2CDF09760095EC3 /* BASSGaplessAudioPlayer-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "BASSGaplessAudioPlayer-dummy.m"; sourceTree = ""; }; + 03E12B1D7C2DA8E97F2AEC9DBBA4BB16 /* Interpolate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Interpolate.h; path = Interpolate/Interpolate.h; sourceTree = ""; }; + 05FBC77B1E082351F79B38317AD7B1EB /* SpringInterpolation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringInterpolation.swift; path = Interpolate/SpringInterpolation.swift; sourceTree = ""; }; + 0B1BB7463FE6D089000505026AD843BB /* Interpolate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Interpolate.framework; path = Interpolate.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 16DB1D49A3928383EAEB8807F94AFCDC /* Pods-AGAudioPlayer.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-AGAudioPlayer.modulemap"; sourceTree = ""; }; - 1A8955F1AB5F47DBC1524111B92A880B /* Interpolatable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Interpolatable.swift; path = Interpolate/Interpolatable.swift; sourceTree = ""; }; 1DDF22F3F5B1A336192085BF4E109776 /* Pods-AGAudioPlayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-AGAudioPlayer.release.xcconfig"; sourceTree = ""; }; - 274228006E3F8CF58C4C723E7654B305 /* NapySlider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NapySlider.swift; path = NapySlider/NapySlider.swift; sourceTree = ""; }; - 281F9106CA5C3D6315BCBA75249C7666 /* Interpolate.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Interpolate.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 25AAE89074B5A50BB0FF11064FB27255 /* NapySlider-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "NapySlider-Info.plist"; sourceTree = ""; }; 307640F886D98B5FB530F19B9F1054A6 /* Pods-AGAudioPlayer-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-AGAudioPlayer-dummy.m"; sourceTree = ""; }; - 32498FB8827F77D746FEBF8CA1973FDC /* BASSGaplessAudioPlayer.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = BASSGaplessAudioPlayer.modulemap; sourceTree = ""; }; - 382EA22CE387B7FDB495B47094EFAD64 /* NapySlider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NapySlider.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3A76B7F4FE259EC6E4DED51527A65F79 /* Interpolate-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Interpolate-prefix.pch"; sourceTree = ""; }; - 40F50EE17EE0402B778FA5028B17C460 /* MarqueeLabel.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MarqueeLabel.xcconfig; sourceTree = ""; }; - 431B9AEEBEF6525AF7F0BE79DAF4EEAC /* BASSGaplessAudioPlayer-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "BASSGaplessAudioPlayer-umbrella.h"; sourceTree = ""; }; - 458253104CE91517F7B9ADE0EB532420 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; - 4786BAC1DA89E012B0E2CEB92968B684 /* bass.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bass.h; path = "BASS Audio Test/bass.h"; sourceTree = ""; }; - 489335E885CB1D9A519CA238B2930135 /* MarqueeLabel.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MarqueeLabel.modulemap; sourceTree = ""; }; - 4FF306EAC475D248C1E97159A904D82D /* Interpolate-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Interpolate-dummy.m"; sourceTree = ""; }; - 5280BB1A1FB91AE339EE6A265EDFDBFE /* MarqueeLabel-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MarqueeLabel-prefix.pch"; sourceTree = ""; }; - 532DF91EBF364C0034524EE3D1F7596D /* BASSGaplessAudioPlayer-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "BASSGaplessAudioPlayer-prefix.pch"; sourceTree = ""; }; - 53DDEACD638180ABAF3D93015F3A6234 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; - 540CD64EBFCF9B8928139B99FCDE7C51 /* BASSGaplessAudioPlayer-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "BASSGaplessAudioPlayer-dummy.m"; sourceTree = ""; }; - 5769BA40B0151D47D2E70FA0ED7306A5 /* Interpolate.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Interpolate.xcconfig; sourceTree = ""; }; - 6E064C6194985EC358526BF39ABFFBC0 /* BASSGaplessAudioPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BASSGaplessAudioPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7369132A6E0B80E7F3259CDC5EF10277 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; - 73BF4D51B00BAD619B8A51DE57B82293 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; }; - 7B2FFAA4F174460C5E52E658EB0DC5EC /* ObjectiveBASS.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ObjectiveBASS.h; path = "BASS Audio Test/ObjectiveBASS.h"; sourceTree = ""; }; - 7DAFE1E26CDE041415C18B1C7737D5D3 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; - 7EBFE319C39F843DB06DE302437CB890 /* BASSGaplessAudioPlayer.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = BASSGaplessAudioPlayer.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 82FB224B257650A87831517C474E7E85 /* NapySlider.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = NapySlider.xcconfig; sourceTree = ""; }; + 339EA850E1B4F980AC9AC6C2E43EBAD1 /* NapySlider-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "NapySlider-prefix.pch"; sourceTree = ""; }; + 33C3579C2ED1F40096F11255010EDBB4 /* Pods_AGAudioPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_AGAudioPlayer.framework; path = "Pods-AGAudioPlayer.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 3643E6D7B44CB9DEAF0558632165D1FB /* libbass_fx.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libbass_fx.a; path = "BASS Audio Test/libbass_fx.a"; sourceTree = ""; }; + 445BAC08A79C64949D5E88F42C0A29EC /* MarqueeLabel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MarqueeLabel.swift; path = Sources/MarqueeLabel.swift; sourceTree = ""; }; + 449808036D39DCE9C36549B56F4B416E /* ObjectiveBASS.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ObjectiveBASS.h; path = "BASS Audio Test/ObjectiveBASS.h"; sourceTree = ""; }; + 45347CF63FC8C661DE81B7DA4A6E7AA3 /* BASSGaplessAudioPlayer.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = BASSGaplessAudioPlayer.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 46D29586B4DF93D02D94CC778DD31C8E /* MarqueeLabel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MarqueeLabel.debug.xcconfig; sourceTree = ""; }; + 47574FDB25394C63FFDBF8CBA3E34542 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; + 48507D79CF3FD7630846A83A242706F3 /* BASSGaplessAudioPlayer-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "BASSGaplessAudioPlayer-Info.plist"; sourceTree = ""; }; + 4B873A5F2C2EFC9169898165B53C54F2 /* bass.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bass.h; path = "BASS Audio Test/bass.h"; sourceTree = ""; }; + 50FD7725B899B3F39889CABCD61D3309 /* Interpolate-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Interpolate-prefix.pch"; sourceTree = ""; }; + 54207A88F5B4B8FA3B3895C3062469AD /* libbassmix.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libbassmix.a; path = "BASS Audio Test/libbassmix.a"; sourceTree = ""; }; + 551EC5116EA77271B892D1C523771E7C /* libbass.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libbass.a; path = "BASS Audio Test/libbass.a"; sourceTree = ""; }; + 5C6985B0E902290F51F011A7442C1C9C /* BASSGaplessAudioPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = BASSGaplessAudioPlayer.framework; path = BASSGaplessAudioPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6046513E6AF129208CF2E6653AD2A694 /* BASSGaplessAudioPlayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = BASSGaplessAudioPlayer.release.xcconfig; sourceTree = ""; }; + 631AF84814149A3DDE8F797F61A31DD7 /* Interpolate-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Interpolate-Info.plist"; sourceTree = ""; }; + 64AD13B92C34D9A459335780C4556B21 /* Interpolate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Interpolate.swift; path = Interpolate/Interpolate.swift; sourceTree = ""; }; + 65E4EB4434BC04DFA34D2B815B4DB15D /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; + 68860F76C7921C9D53C1D5C9163E2021 /* NapySlider.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = NapySlider.release.xcconfig; sourceTree = ""; }; + 6952A4D3D1C8DCC9075B8B425D3D4A1D /* NapySlider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = NapySlider.framework; path = NapySlider.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6FC37950EFE6CA2ECB0C174F38E15991 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE; sourceTree = ""; }; + 769349A6FD16FCD1EB1E3ADFE814F710 /* BASSGaplessAudioPlayer-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "BASSGaplessAudioPlayer-prefix.pch"; sourceTree = ""; }; + 78F2FC0531AF008A2C35C66D1C22A081 /* Interpolate.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Interpolate.modulemap; sourceTree = ""; }; + 7D2FCD11DC7B82CBAB4DBEAC183C64DD /* BASSGaplessAudioPlayer.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = BASSGaplessAudioPlayer.modulemap; sourceTree = ""; }; + 8115BD556FB1A3CBE4E55E26790EE72B /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; }; + 82D85BAA8D425B9474900DC28E87F93E /* NapySlider-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "NapySlider-umbrella.h"; sourceTree = ""; }; 83476A1431D492B3CD8299BE591BE5A9 /* Pods-AGAudioPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-AGAudioPlayer.debug.xcconfig"; sourceTree = ""; }; - 844762784726A1166728623B9E86F615 /* Interpolate.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = Interpolate.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 86E6F0FE7E08AFE6BD95000C8D795582 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; - 87B7410AA702A125875A21A472179101 /* MarqueeLabel-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MarqueeLabel-umbrella.h"; sourceTree = ""; }; - 880F1F3DD6416E47D95FCFF808332C9E /* NapySlider-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "NapySlider-dummy.m"; sourceTree = ""; }; - 8A3F83AA70224466B9FED21BF4C56F9C /* MarqueeLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MarqueeLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8A4C4DB0C2C36C32DA1310DCB0D47B4A /* NapySlider.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = NapySlider.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 8A5623973652E868FE85BEE064678DED /* libbass_fx.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libbass_fx.a; path = "BASS Audio Test/libbass_fx.a"; sourceTree = ""; }; - 8C0093CC370B28EC079B3E16F69473B4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - 921D80B2BB5563E37564FA4129C8F5B0 /* MarqueeLabel-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "MarqueeLabel-Info.plist"; sourceTree = ""; }; - 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - A0AE4A6ED8711F57E92E2F21A8217EB3 /* BASSGaplessAudioPlayer.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = BASSGaplessAudioPlayer.xcconfig; sourceTree = ""; }; - A21F8879D0FB1DE6038E570D21E578CB /* NapySlider.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = NapySlider.modulemap; sourceTree = ""; }; - A56DB7536E6DB8BED825692E020E9852 /* Interpolate-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Interpolate-umbrella.h"; sourceTree = ""; }; - A90B959B5840715C6FB6917FC16D8F58 /* Interpolate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Interpolate.swift; path = Interpolate/Interpolate.swift; sourceTree = ""; }; + 83CEE7933A3D4ACA37EB0154538D5EEB /* Interpolate.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Interpolate.release.xcconfig; sourceTree = ""; }; + 87CECE363BB082CBA4E652DD3E203207 /* MarqueeLabel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MarqueeLabel.release.xcconfig; sourceTree = ""; }; + 88D2A3E3E19BEF49E44621413D499D73 /* Interpolate-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Interpolate-dummy.m"; sourceTree = ""; }; + 893B0F76DBD07C23DD654D2FFCA11852 /* BASSGaplessAudioPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = BASSGaplessAudioPlayer.debug.xcconfig; sourceTree = ""; }; + 8C4C3228FBDAD0409877F32075F75250 /* BASSGaplessAudioPlayer-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "BASSGaplessAudioPlayer-umbrella.h"; sourceTree = ""; }; + 90F5F1165D9AB46DAA4B2C8A3B97E39C /* NapySlider.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = NapySlider.debug.xcconfig; sourceTree = ""; }; + 932FCC4ADDD42C7297657D11A90C4D4C /* MarqueeLabel-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "MarqueeLabel-Info.plist"; sourceTree = ""; }; + 963E1ECAAD3093CD9A7A193BD5C439E9 /* Interpolatable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Interpolatable.swift; path = Interpolate/Interpolatable.swift; sourceTree = ""; }; + 96F0E33FA32CDB7C91F8893DAE67A53E /* NapySlider.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = NapySlider.modulemap; sourceTree = ""; }; + 9935058FEF015B9A4DFCFBDB1CAFB559 /* MarqueeLabel.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MarqueeLabel.modulemap; sourceTree = ""; }; + 99973F10E433E52E6CB9C03F0AE81E10 /* bass_fx.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bass_fx.h; path = "BASS Audio Test/bass_fx.h"; sourceTree = ""; }; + 9AD49DF7F7A8018A405794057F45B02E /* bassmix.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bassmix.h; path = "BASS Audio Test/bassmix.h"; sourceTree = ""; }; + 9D06F44B6F1D454EB08F649853397BA2 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; + 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; }; + 9FB339A4A552294BA385A565BCCB9D7A /* MarqueeLabel-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MarqueeLabel-umbrella.h"; sourceTree = ""; }; + A7101FF48687E763E7A4FF2220F620B7 /* 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; }; + AA8497B44E9CF89DEAFF36CEE598247E /* 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; }; AAF752C63D4E09DBD560612EED7FDD77 /* Pods-AGAudioPlayer-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-AGAudioPlayer-umbrella.h"; sourceTree = ""; }; - B1B8935D5C98F0C9FE93EE7F00A20701 /* bassmix.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bassmix.h; path = "BASS Audio Test/bassmix.h"; sourceTree = ""; }; - B28773E3B3C02BDAEFF9F7C6A13234CF /* bass_fx.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bass_fx.h; path = "BASS Audio Test/bass_fx.h"; sourceTree = ""; }; - BB4D13DEF97CD3BA933E2B2C34A31BC2 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + AFD4B5CB75169B7D5D2801BFE50E8303 /* NapySlider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NapySlider.swift; path = NapySlider/NapySlider.swift; sourceTree = ""; }; + B39AD3BD156F512505171E9161471454 /* Interpolate-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Interpolate-umbrella.h"; sourceTree = ""; }; BB4D451DB3D21EA5C48DE4D006AB9EDA /* Pods-AGAudioPlayer-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-AGAudioPlayer-Info.plist"; sourceTree = ""; }; - BBFF6C5262A13A49F9270EE60040F621 /* Pods_AGAudioPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AGAudioPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BF22209231A18D8F188E75C2F190E2A0 /* ObjectiveBASS.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = ObjectiveBASS.m; path = "BASS Audio Test/ObjectiveBASS.m"; sourceTree = ""; }; - C4FB47A2FBDD8DAAA5569426552F5C4B /* SpringInterpolation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringInterpolation.swift; path = Interpolate/SpringInterpolation.swift; sourceTree = ""; }; - C564755FA1097CCB1C6F0C0B0249B770 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; - C906CB5074C13AE46734F708A45E767E /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - CA9F1521BD011C22712532162D584A4B /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - CB1EC2EC0B3896291B433A14C9DC3CD9 /* Interpolate.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Interpolate.modulemap; sourceTree = ""; }; - D16BF44054C135C9CE23F338269DA717 /* NapySlider-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "NapySlider-prefix.pch"; sourceTree = ""; }; - D60565EB9DCB2758274A8A02FF2A0320 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; }; - D6264F5CF81D95E7024A6628C52816AD /* Interpolate-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Interpolate-Info.plist"; sourceTree = ""; }; + CEFE5867B2DAD43D6916B66FC48FFC70 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; + CF0AA9FBFBDB70858C030769541505ED /* MarqueeLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = MarqueeLabel.framework; path = MarqueeLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D6F3BEE74B3EB201843E9082A9B4DC49 /* Pods-AGAudioPlayer-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-AGAudioPlayer-acknowledgements.markdown"; sourceTree = ""; }; - DD095DFBF50403132A0958F8EB6DD14C /* LICENSE.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; }; DE4E0236DEC67388899D0C7BEC4F59E8 /* Pods-AGAudioPlayer-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-AGAudioPlayer-frameworks.sh"; sourceTree = ""; }; - E5A9E95E39B2019A95C02C5E2119072D /* libbassmix.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libbassmix.a; path = "BASS Audio Test/libbassmix.a"; sourceTree = ""; }; - EB8DCA14C457B173D8BCE0ED6E605189 /* libbass.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; name = libbass.a; path = "BASS Audio Test/libbass.a"; sourceTree = ""; }; + E16A3A1BABEC0E6FAD525B3779B69C22 /* NapySlider-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "NapySlider-dummy.m"; sourceTree = ""; }; + E4BB5851DD44B4185DBB94A2F1A93085 /* Interpolate.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Interpolate.debug.xcconfig; sourceTree = ""; }; EF27BDFB9E7FBFDE5638F6EAF6DC7677 /* Pods-AGAudioPlayer-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-AGAudioPlayer-acknowledgements.plist"; sourceTree = ""; }; - F1404CB31839B4066F9B2DE1424821BB /* MarqueeLabel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MarqueeLabel.m; path = Sources/ObjC/MarqueeLabel.m; sourceTree = ""; }; - F50AD6D3FF4576CD0AF6EEE58B4EC608 /* MarqueeLabel-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "MarqueeLabel-dummy.m"; sourceTree = ""; }; - F64729CDCF9B7A43091DD55E428BA954 /* BASSGaplessAudioPlayer-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "BASSGaplessAudioPlayer-Info.plist"; sourceTree = ""; }; - FC3BC8D64B1FF838633F1BFB1A4D2598 /* MarqueeLabel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MarqueeLabel.h; path = Sources/ObjC/MarqueeLabel.h; sourceTree = ""; }; + FB6B50DC4232E11243786EF5C5A9F6BC /* ObjectiveBASS.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = ObjectiveBASS.m; path = "BASS Audio Test/ObjectiveBASS.m"; sourceTree = ""; }; + FB9A82856F25A1E8466AD58C682AC82C /* MarqueeLabel-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MarqueeLabel-prefix.pch"; sourceTree = ""; }; + FCBF85811ABE2D31327A21FC025BC4F5 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; }; + FFE051EA6D5A288F4ACAC618BC0015B6 /* BasicInterpolation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BasicInterpolation.swift; path = Interpolate/BasicInterpolation.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 149429C2161171E83F28A0C0C2A5A130 /* Frameworks */ = { + 1A6ABFB3F71ADA7F9622DEC9B7A3BDF4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1674B2F944517C6E6E3EC22E59734D83 /* Accelerate.framework in Frameworks */, - 8FE0C33F0EAF94EAE7360DDC8DB718FE /* AudioToolbox.framework in Frameworks */, - FFC94BB458FADE168ADCC826BA75DCE7 /* AVFoundation.framework in Frameworks */, - D3C29D5F100517A9C081C97C2FAB1F02 /* CFNetwork.framework in Frameworks */, - 04C65DA88F744676EC9665E2B406E86F /* Foundation.framework in Frameworks */, - 2E6A5DB2EEB0163621E9F1B4C5AA3A5B /* SystemConfiguration.framework in Frameworks */, + E2BAAB41FAF2ABB257F90E7F6F3BA4DF /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 1E07408F439DF18F6E00E57E5F98802C /* Frameworks */ = { + 4274CA0E731AECC68C24808C7E6703AA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 776296316A3C8280B40496CB97B5C859 /* Foundation.framework in Frameworks */, - EDA1087BB8E333A30B30B2A0B99032F3 /* QuartzCore.framework in Frameworks */, + CA6B7B11EAE51C6E3453876018130527 /* Foundation.framework in Frameworks */, + CADD2A1613A4CBD5023DD8ECD06DFBCC /* QuartzCore.framework in Frameworks */, + E771CDF7837319A49468CC35D18D8434 /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 3A9938CAE8D7BC132F6E93FB08A7A3DF /* Frameworks */ = { + 8DA82DD62D7752C9807F448BC1C99039 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AB0CE01ED1B3A358D14B2B8133C66FB7 /* Foundation.framework in Frameworks */, - 769ACB66C78813C45EEEA361954F2FD9 /* QuartzCore.framework in Frameworks */, - BEBE27F2D0DDF50913A65C819BF5FD0A /* UIKit.framework in Frameworks */, + 5E5CD62A44974AA675EC22DCE3DD3B8B /* Accelerate.framework in Frameworks */, + BA87DAC94CCFD94B2C960C7F3C1639FA /* AudioToolbox.framework in Frameworks */, + EEBFA31D279AC93F0B9FDCC1B18EB48C /* AVFoundation.framework in Frameworks */, + 90E03814819D335B5F0784F62C5AE92B /* CFNetwork.framework in Frameworks */, + 37C514D75917BD2FBC6789A6ED50E780 /* Foundation.framework in Frameworks */, + 3249E6DD0EC7BC3D28A17B2788E69360 /* SystemConfiguration.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 9443866A531D464BF78A2E54A5D6C471 /* Frameworks */ = { + 93E91658F755D8E6D1B28E734A21DEE6 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D94CA838EBF30A78E2C6FCB1D4817D74 /* Foundation.framework in Frameworks */, + 30110AED9A917C9623959A5A33BEC6D2 /* Foundation.framework in Frameworks */, + AEABDD2270E3533912D4C9A8D36C6436 /* QuartzCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - B37D5F6E8291D067F50FE7364CB290D4 /* Frameworks */ = { + C3C5A77C163E9220A1843D414A4BB0BF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 380FBEAFB6C5E2A468B8F8E1ABF6E47F /* Foundation.framework in Frameworks */, + 70302383A232F13569F5C63A5F2A53A9 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 01856F6121D60F6E816FBF5D7EFB22EE /* MarqueeLabel */ = { - isa = PBXGroup; - children = ( - A07309D8E5A6771FB2E1F332BB031204 /* ObjC */, - E073C78BA9E53623E6DA8B6715D7028B /* Support Files */, - ); - path = MarqueeLabel; - sourceTree = ""; - }; 12753F70819F9241988F98EFEC136F0C /* Products */ = { isa = PBXGroup; children = ( - 6E064C6194985EC358526BF39ABFFBC0 /* BASSGaplessAudioPlayer.framework */, - 281F9106CA5C3D6315BCBA75249C7666 /* Interpolate.framework */, - 8A3F83AA70224466B9FED21BF4C56F9C /* MarqueeLabel.framework */, - 382EA22CE387B7FDB495B47094EFAD64 /* NapySlider.framework */, - BBFF6C5262A13A49F9270EE60040F621 /* Pods_AGAudioPlayer.framework */, + 5C6985B0E902290F51F011A7442C1C9C /* BASSGaplessAudioPlayer.framework */, + 0B1BB7463FE6D089000505026AD843BB /* Interpolate.framework */, + CF0AA9FBFBDB70858C030769541505ED /* MarqueeLabel.framework */, + 6952A4D3D1C8DCC9075B8B425D3D4A1D /* NapySlider.framework */, + 33C3579C2ED1F40096F11255010EDBB4 /* Pods_AGAudioPlayer.framework */, ); name = Products; sourceTree = ""; }; - 12D8AB1AA7E0444A189A814243DE9740 /* Pod */ = { + 13380DA5612211DC94D04187A499490B /* Pods */ = { isa = PBXGroup; children = ( - 844762784726A1166728623B9E86F615 /* Interpolate.podspec */, - BB4D13DEF97CD3BA933E2B2C34A31BC2 /* LICENSE */, - C906CB5074C13AE46734F708A45E767E /* README.md */, + 6F38C7E285C57AEA0FB53B5E3CC02D83 /* Interpolate */, + 79757069234EEC46E480478BC722F606 /* MarqueeLabel */, + 3218D9F46C03BACE0979FEA53012D36F /* NapySlider */, ); - name = Pod; + name = Pods; sourceTree = ""; }; - 3422DE1AF5F8089C2A395D004A60A79D /* iOS */ = { + 3218D9F46C03BACE0979FEA53012D36F /* NapySlider */ = { isa = PBXGroup; children = ( - D60565EB9DCB2758274A8A02FF2A0320 /* Accelerate.framework */, - 73BF4D51B00BAD619B8A51DE57B82293 /* AudioToolbox.framework */, - 458253104CE91517F7B9ADE0EB532420 /* AVFoundation.framework */, - 53DDEACD638180ABAF3D93015F3A6234 /* CFNetwork.framework */, - 8C0093CC370B28EC079B3E16F69473B4 /* Foundation.framework */, - C564755FA1097CCB1C6F0C0B0249B770 /* QuartzCore.framework */, - 86E6F0FE7E08AFE6BD95000C8D795582 /* SystemConfiguration.framework */, - 7369132A6E0B80E7F3259CDC5EF10277 /* UIKit.framework */, + AFD4B5CB75169B7D5D2801BFE50E8303 /* NapySlider.swift */, + 4C84937792C0C3A87EC174910F78C844 /* Support Files */, ); - name = iOS; + name = NapySlider; + path = NapySlider; sourceTree = ""; }; - 41D7201250A865B773DEE9FE34335CF6 /* Development Pods */ = { + 3598D54FACC6935D12592881C23CA656 /* Support Files */ = { isa = PBXGroup; children = ( - 9C89214702DCE54BCC7505E87799FF2D /* BASSGaplessAudioPlayer */, - D4EA94944A45B4FB96E9C13276B161DA /* Interpolate */, - 9AA3EF0107207DBB691A34E6996168FD /* NapySlider */, + 78F2FC0531AF008A2C35C66D1C22A081 /* Interpolate.modulemap */, + 88D2A3E3E19BEF49E44621413D499D73 /* Interpolate-dummy.m */, + 631AF84814149A3DDE8F797F61A31DD7 /* Interpolate-Info.plist */, + 50FD7725B899B3F39889CABCD61D3309 /* Interpolate-prefix.pch */, + B39AD3BD156F512505171E9161471454 /* Interpolate-umbrella.h */, + E4BB5851DD44B4185DBB94A2F1A93085 /* Interpolate.debug.xcconfig */, + 83CEE7933A3D4ACA37EB0154538D5EEB /* Interpolate.release.xcconfig */, ); - name = "Development Pods"; + name = "Support Files"; + path = "../Target Support Files/Interpolate"; sourceTree = ""; }; - 56DC1EA6D6A2DFD88A326C95816F08AE /* Pod */ = { + 40BE9C9D1EADF15A9A06864632A59E91 /* BASSGaplessAudioPlayer */ = { isa = PBXGroup; children = ( - 7EBFE319C39F843DB06DE302437CB890 /* BASSGaplessAudioPlayer.podspec */, - 7DAFE1E26CDE041415C18B1C7737D5D3 /* LICENSE */, + 4B873A5F2C2EFC9169898165B53C54F2 /* bass.h */, + 99973F10E433E52E6CB9C03F0AE81E10 /* bass_fx.h */, + 9AD49DF7F7A8018A405794057F45B02E /* bassmix.h */, + 449808036D39DCE9C36549B56F4B416E /* ObjectiveBASS.h */, + FB6B50DC4232E11243786EF5C5A9F6BC /* ObjectiveBASS.m */, + 6468B6C9CF07F1EE82286CA3978F4719 /* Frameworks */, + 9AB6D8A352E1594F1C6810F9F22246D0 /* Pod */, + 5F451353A613E8A9E882DC8AD362C6C9 /* Support Files */, ); - name = Pod; + name = BASSGaplessAudioPlayer; + path = "../../gapless-audio-bass-ios"; sourceTree = ""; }; - 79CFA6C6F92E36996E60A57AC0C3147C /* Support Files */ = { + 4C84937792C0C3A87EC174910F78C844 /* Support Files */ = { isa = PBXGroup; children = ( - CB1EC2EC0B3896291B433A14C9DC3CD9 /* Interpolate.modulemap */, - 5769BA40B0151D47D2E70FA0ED7306A5 /* Interpolate.xcconfig */, - 4FF306EAC475D248C1E97159A904D82D /* Interpolate-dummy.m */, - D6264F5CF81D95E7024A6628C52816AD /* Interpolate-Info.plist */, - 3A76B7F4FE259EC6E4DED51527A65F79 /* Interpolate-prefix.pch */, - A56DB7536E6DB8BED825692E020E9852 /* Interpolate-umbrella.h */, + 96F0E33FA32CDB7C91F8893DAE67A53E /* NapySlider.modulemap */, + E16A3A1BABEC0E6FAD525B3779B69C22 /* NapySlider-dummy.m */, + 25AAE89074B5A50BB0FF11064FB27255 /* NapySlider-Info.plist */, + 339EA850E1B4F980AC9AC6C2E43EBAD1 /* NapySlider-prefix.pch */, + 82D85BAA8D425B9474900DC28E87F93E /* NapySlider-umbrella.h */, + 90F5F1165D9AB46DAA4B2C8A3B97E39C /* NapySlider.debug.xcconfig */, + 68860F76C7921C9D53C1D5C9163E2021 /* NapySlider.release.xcconfig */, ); name = "Support Files"; - path = "../AGAudioPlayer/Pods/Target Support Files/Interpolate"; - sourceTree = ""; - }; - 9165A3E161B88C11C0E5EBF02DDFA56C /* Targets Support Files */ = { - isa = PBXGroup; - children = ( - ECE8770B3AE5AE6DE491621E1D1DEBE5 /* Pods-AGAudioPlayer */, - ); - name = "Targets Support Files"; + path = "../Target Support Files/NapySlider"; sourceTree = ""; }; - 9AA3EF0107207DBB691A34E6996168FD /* NapySlider */ = { + 5F451353A613E8A9E882DC8AD362C6C9 /* Support Files */ = { isa = PBXGroup; children = ( - 274228006E3F8CF58C4C723E7654B305 /* NapySlider.swift */, - EAF21D4BDFD5D01D593748A3B40DAC10 /* Pod */, - E5F4DF318B90CBCA6C726CA2A4B61BD9 /* Support Files */, + 7D2FCD11DC7B82CBAB4DBEAC183C64DD /* BASSGaplessAudioPlayer.modulemap */, + 034F1B8838A5E28AB2CDF09760095EC3 /* BASSGaplessAudioPlayer-dummy.m */, + 48507D79CF3FD7630846A83A242706F3 /* BASSGaplessAudioPlayer-Info.plist */, + 769349A6FD16FCD1EB1E3ADFE814F710 /* BASSGaplessAudioPlayer-prefix.pch */, + 8C4C3228FBDAD0409877F32075F75250 /* BASSGaplessAudioPlayer-umbrella.h */, + 893B0F76DBD07C23DD654D2FFCA11852 /* BASSGaplessAudioPlayer.debug.xcconfig */, + 6046513E6AF129208CF2E6653AD2A694 /* BASSGaplessAudioPlayer.release.xcconfig */, ); - name = NapySlider; - path = ../../NapySlider; + name = "Support Files"; + path = "../AGAudioPlayer/Pods/Target Support Files/BASSGaplessAudioPlayer"; sourceTree = ""; }; - 9C89214702DCE54BCC7505E87799FF2D /* BASSGaplessAudioPlayer */ = { + 6468B6C9CF07F1EE82286CA3978F4719 /* Frameworks */ = { isa = PBXGroup; children = ( - 4786BAC1DA89E012B0E2CEB92968B684 /* bass.h */, - B28773E3B3C02BDAEFF9F7C6A13234CF /* bass_fx.h */, - B1B8935D5C98F0C9FE93EE7F00A20701 /* bassmix.h */, - 7B2FFAA4F174460C5E52E658EB0DC5EC /* ObjectiveBASS.h */, - BF22209231A18D8F188E75C2F190E2A0 /* ObjectiveBASS.m */, - A8949A6ACA832B3DDDA61B8B2C198ECF /* Frameworks */, - 56DC1EA6D6A2DFD88A326C95816F08AE /* Pod */, - EB2EF33392779C2F8325DCDFA8975C72 /* Support Files */, + 551EC5116EA77271B892D1C523771E7C /* libbass.a */, + 3643E6D7B44CB9DEAF0558632165D1FB /* libbass_fx.a */, + 54207A88F5B4B8FA3B3895C3062469AD /* libbassmix.a */, ); - name = BASSGaplessAudioPlayer; - path = "../../gapless-audio-bass-ios"; + name = Frameworks; sourceTree = ""; }; - A07309D8E5A6771FB2E1F332BB031204 /* ObjC */ = { + 6F38C7E285C57AEA0FB53B5E3CC02D83 /* Interpolate */ = { isa = PBXGroup; children = ( - FC3BC8D64B1FF838633F1BFB1A4D2598 /* MarqueeLabel.h */, - F1404CB31839B4066F9B2DE1424821BB /* MarqueeLabel.m */, + FFE051EA6D5A288F4ACAC618BC0015B6 /* BasicInterpolation.swift */, + 963E1ECAAD3093CD9A7A193BD5C439E9 /* Interpolatable.swift */, + 03E12B1D7C2DA8E97F2AEC9DBBA4BB16 /* Interpolate.h */, + 64AD13B92C34D9A459335780C4556B21 /* Interpolate.swift */, + 05FBC77B1E082351F79B38317AD7B1EB /* SpringInterpolation.swift */, + 3598D54FACC6935D12592881C23CA656 /* Support Files */, ); - name = ObjC; + name = Interpolate; + path = Interpolate; sourceTree = ""; }; - A8949A6ACA832B3DDDA61B8B2C198ECF /* Frameworks */ = { + 79757069234EEC46E480478BC722F606 /* MarqueeLabel */ = { isa = PBXGroup; children = ( - EB8DCA14C457B173D8BCE0ED6E605189 /* libbass.a */, - 8A5623973652E868FE85BEE064678DED /* libbass_fx.a */, - E5A9E95E39B2019A95C02C5E2119072D /* libbassmix.a */, + 445BAC08A79C64949D5E88F42C0A29EC /* MarqueeLabel.swift */, + A8B95158BED4D86AD9C2B81B9C755B75 /* Support Files */, ); - name = Frameworks; + name = MarqueeLabel; + path = MarqueeLabel; sourceTree = ""; }; - CF1408CF629C7361332E53B88F7BD30C = { + 9165A3E161B88C11C0E5EBF02DDFA56C /* Targets Support Files */ = { isa = PBXGroup; children = ( - 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, - 41D7201250A865B773DEE9FE34335CF6 /* Development Pods */, - F119B4A0ABE017AECEE69836596133B2 /* Frameworks */, - F89CF82BFB6B29D57B3ED666A4980FA6 /* Pods */, - 12753F70819F9241988F98EFEC136F0C /* Products */, - 9165A3E161B88C11C0E5EBF02DDFA56C /* Targets Support Files */, + ECE8770B3AE5AE6DE491621E1D1DEBE5 /* Pods-AGAudioPlayer */, ); + name = "Targets Support Files"; sourceTree = ""; }; - D4EA94944A45B4FB96E9C13276B161DA /* Interpolate */ = { + 9AB6D8A352E1594F1C6810F9F22246D0 /* Pod */ = { isa = PBXGroup; children = ( - 0F88747EA13634931FA51285F2700B3A /* BasicInterpolation.swift */, - 1A8955F1AB5F47DBC1524111B92A880B /* Interpolatable.swift */, - 031A192D2BCE6031289DF14271500286 /* Interpolate.h */, - A90B959B5840715C6FB6917FC16D8F58 /* Interpolate.swift */, - C4FB47A2FBDD8DAAA5569426552F5C4B /* SpringInterpolation.swift */, - 12D8AB1AA7E0444A189A814243DE9740 /* Pod */, - 79CFA6C6F92E36996E60A57AC0C3147C /* Support Files */, + 45347CF63FC8C661DE81B7DA4A6E7AA3 /* BASSGaplessAudioPlayer.podspec */, + 6FC37950EFE6CA2ECB0C174F38E15991 /* LICENSE */, ); - name = Interpolate; - path = ../../Interpolate; + name = Pod; sourceTree = ""; }; - E073C78BA9E53623E6DA8B6715D7028B /* Support Files */ = { + A8B95158BED4D86AD9C2B81B9C755B75 /* Support Files */ = { isa = PBXGroup; children = ( - 489335E885CB1D9A519CA238B2930135 /* MarqueeLabel.modulemap */, - 40F50EE17EE0402B778FA5028B17C460 /* MarqueeLabel.xcconfig */, - F50AD6D3FF4576CD0AF6EEE58B4EC608 /* MarqueeLabel-dummy.m */, - 921D80B2BB5563E37564FA4129C8F5B0 /* MarqueeLabel-Info.plist */, - 5280BB1A1FB91AE339EE6A265EDFDBFE /* MarqueeLabel-prefix.pch */, - 87B7410AA702A125875A21A472179101 /* MarqueeLabel-umbrella.h */, + 9935058FEF015B9A4DFCFBDB1CAFB559 /* MarqueeLabel.modulemap */, + 02C73980B515157CA57547B0E246BC0D /* MarqueeLabel-dummy.m */, + 932FCC4ADDD42C7297657D11A90C4D4C /* MarqueeLabel-Info.plist */, + FB9A82856F25A1E8466AD58C682AC82C /* MarqueeLabel-prefix.pch */, + 9FB339A4A552294BA385A565BCCB9D7A /* MarqueeLabel-umbrella.h */, + 46D29586B4DF93D02D94CC778DD31C8E /* MarqueeLabel.debug.xcconfig */, + 87CECE363BB082CBA4E652DD3E203207 /* MarqueeLabel.release.xcconfig */, ); name = "Support Files"; path = "../Target Support Files/MarqueeLabel"; sourceTree = ""; }; - E5F4DF318B90CBCA6C726CA2A4B61BD9 /* Support Files */ = { + B6119166D3B76C4E70E241DD599DBE42 /* iOS */ = { isa = PBXGroup; children = ( - A21F8879D0FB1DE6038E570D21E578CB /* NapySlider.modulemap */, - 82FB224B257650A87831517C474E7E85 /* NapySlider.xcconfig */, - 880F1F3DD6416E47D95FCFF808332C9E /* NapySlider-dummy.m */, - 059DFD3E8A04B57A637E82149B6CB834 /* NapySlider-Info.plist */, - D16BF44054C135C9CE23F338269DA717 /* NapySlider-prefix.pch */, - 10764428BEEC44CF067CC511AF86283E /* NapySlider-umbrella.h */, + FCBF85811ABE2D31327A21FC025BC4F5 /* Accelerate.framework */, + 8115BD556FB1A3CBE4E55E26790EE72B /* AudioToolbox.framework */, + 47574FDB25394C63FFDBF8CBA3E34542 /* AVFoundation.framework */, + 65E4EB4434BC04DFA34D2B815B4DB15D /* CFNetwork.framework */, + A7101FF48687E763E7A4FF2220F620B7 /* Foundation.framework */, + CEFE5867B2DAD43D6916B66FC48FFC70 /* QuartzCore.framework */, + 9D06F44B6F1D454EB08F649853397BA2 /* SystemConfiguration.framework */, + AA8497B44E9CF89DEAFF36CEE598247E /* UIKit.framework */, ); - name = "Support Files"; - path = "../AGAudioPlayer/Pods/Target Support Files/NapySlider"; + name = iOS; sourceTree = ""; }; - EAF21D4BDFD5D01D593748A3B40DAC10 /* Pod */ = { + CF1408CF629C7361332E53B88F7BD30C = { isa = PBXGroup; children = ( - DD095DFBF50403132A0958F8EB6DD14C /* LICENSE.md */, - 8A4C4DB0C2C36C32DA1310DCB0D47B4A /* NapySlider.podspec */, - CA9F1521BD011C22712532162D584A4B /* README.md */, + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + D5A629A91731FBBF371E0A253A2121DD /* Development Pods */, + F119B4A0ABE017AECEE69836596133B2 /* Frameworks */, + 13380DA5612211DC94D04187A499490B /* Pods */, + 12753F70819F9241988F98EFEC136F0C /* Products */, + 9165A3E161B88C11C0E5EBF02DDFA56C /* Targets Support Files */, ); - name = Pod; sourceTree = ""; }; - EB2EF33392779C2F8325DCDFA8975C72 /* Support Files */ = { + D5A629A91731FBBF371E0A253A2121DD /* Development Pods */ = { isa = PBXGroup; children = ( - 32498FB8827F77D746FEBF8CA1973FDC /* BASSGaplessAudioPlayer.modulemap */, - A0AE4A6ED8711F57E92E2F21A8217EB3 /* BASSGaplessAudioPlayer.xcconfig */, - 540CD64EBFCF9B8928139B99FCDE7C51 /* BASSGaplessAudioPlayer-dummy.m */, - F64729CDCF9B7A43091DD55E428BA954 /* BASSGaplessAudioPlayer-Info.plist */, - 532DF91EBF364C0034524EE3D1F7596D /* BASSGaplessAudioPlayer-prefix.pch */, - 431B9AEEBEF6525AF7F0BE79DAF4EEAC /* BASSGaplessAudioPlayer-umbrella.h */, + 40BE9C9D1EADF15A9A06864632A59E91 /* BASSGaplessAudioPlayer */, ); - name = "Support Files"; - path = "../AGAudioPlayer/Pods/Target Support Files/BASSGaplessAudioPlayer"; + name = "Development Pods"; sourceTree = ""; }; ECE8770B3AE5AE6DE491621E1D1DEBE5 /* Pods-AGAudioPlayer */ = { @@ -434,65 +412,56 @@ F119B4A0ABE017AECEE69836596133B2 /* Frameworks */ = { isa = PBXGroup; children = ( - 3422DE1AF5F8089C2A395D004A60A79D /* iOS */, + B6119166D3B76C4E70E241DD599DBE42 /* iOS */, ); name = Frameworks; sourceTree = ""; }; - F89CF82BFB6B29D57B3ED666A4980FA6 /* Pods */ = { - isa = PBXGroup; - children = ( - 01856F6121D60F6E816FBF5D7EFB22EE /* MarqueeLabel */, - ); - name = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 1D05B1AA36B0BB296FBCA19D5F9B013D /* Headers */ = { + 1EB8BF23AF50B6F229D74CBE46E18F31 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 17D10ADFC7CFDC54B366F5864B3419A7 /* bass.h in Headers */, - 778A155DD461946668FB16CE3D568D5E /* bass_fx.h in Headers */, - 621D7DE60B15A0D70C797FBF59499569 /* BASSGaplessAudioPlayer-umbrella.h in Headers */, - 9C67CFBBBEE08E50BA939362A7769E8B /* bassmix.h in Headers */, - 6D67F7261BF63AFB0936BBBE3C6D8B86 /* ObjectiveBASS.h in Headers */, + 82C0B8158E9D5764869040A461043694 /* bass.h in Headers */, + A393DCAFE058E0917CDD5BF0442E26AC /* bass_fx.h in Headers */, + 693E153BB9ADF58542E30A14E0503157 /* BASSGaplessAudioPlayer-umbrella.h in Headers */, + A7870A395B3E7F1C70327A75ABA4796F /* bassmix.h in Headers */, + 689C5EDE87027BC85DAE9DEE0681C540 /* ObjectiveBASS.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - 86CC3A1FB762E6717AD4D9C9E004C23F /* Headers */ = { + 2600FD8911D8C12E6DD1BAFE88E8AEAD /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 46DF40AB8F2C9EE4C8F87DEAEA71463D /* MarqueeLabel-umbrella.h in Headers */, - C881683BD376A842DBBC19FF2D2BCF17 /* MarqueeLabel.h in Headers */, + 4DD3BF565D8F923F1BFE664F3896F6CD /* Pods-AGAudioPlayer-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - 96F1872EF19E99F8ADD808B1E65B8B69 /* Headers */ = { + 286B72DD57618D81760342A3C1C60205 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 9B530806BF8728898EE2BA4D763F8898 /* Interpolate-umbrella.h in Headers */, - 5AA4289D7E9D275A1EC619865F4FCFAA /* Interpolate.h in Headers */, + A09FD26C0D41B65DEB1011AAB095C631 /* NapySlider-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - A01747C42F0799FD9F5F3EE27F333AE2 /* Headers */ = { + 3076D331E9F18C1C52553382CDD01DA8 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 137BA0D4787A3F404C1C95841153CDA5 /* NapySlider-umbrella.h in Headers */, + BD503BE4798FC30D23AC747146D39FE2 /* MarqueeLabel-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - FA42B9CF0EEE685B7404EB9F5C95772B /* Headers */ = { + CCA9F09DA21422F28223E467DEA7A70E /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - F72B35E9A5B0940F5E5A2EF245511D2A /* Pods-AGAudioPlayer-umbrella.h in Headers */, + 310C7A5DFC8B7E026C14D2B2F211E98B /* Interpolate-umbrella.h in Headers */, + 0FE2278C2EB5C497302110A87BDCE16C /* Interpolate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -501,12 +470,12 @@ /* Begin PBXNativeTarget section */ 03AE74D07594E1CB394E8D6D1ACA8180 /* NapySlider */ = { isa = PBXNativeTarget; - buildConfigurationList = F6B4F85B5375EB04FF9BA518A261EA94 /* Build configuration list for PBXNativeTarget "NapySlider" */; + buildConfigurationList = 310EDBA21EC772085F3F2830790BD8B2 /* Build configuration list for PBXNativeTarget "NapySlider" */; buildPhases = ( - A01747C42F0799FD9F5F3EE27F333AE2 /* Headers */, - 79CBD22146971D2F1C9C7B08943CC118 /* Sources */, - B37D5F6E8291D067F50FE7364CB290D4 /* Frameworks */, - 5C3F6FD505E4E2CE7833601F3BFDA7EB /* Resources */, + 286B72DD57618D81760342A3C1C60205 /* Headers */, + 7F87F5EDC0392A2F640E07C03128E758 /* Sources */, + C3C5A77C163E9220A1843D414A4BB0BF /* Frameworks */, + FCE454C9441613F1274C3F7EC0725EF0 /* Resources */, ); buildRules = ( ); @@ -514,17 +483,17 @@ ); name = NapySlider; productName = NapySlider; - productReference = 382EA22CE387B7FDB495B47094EFAD64 /* NapySlider.framework */; + productReference = 6952A4D3D1C8DCC9075B8B425D3D4A1D /* NapySlider.framework */; productType = "com.apple.product-type.framework"; }; 6C7CE3CDC16FE41E5088964C355F522A /* Interpolate */ = { isa = PBXNativeTarget; - buildConfigurationList = 9E4D50409F9E1005883EB1206C75358E /* Build configuration list for PBXNativeTarget "Interpolate" */; + buildConfigurationList = 89B1E22E78BDFFE5567B05422CC73C33 /* Build configuration list for PBXNativeTarget "Interpolate" */; buildPhases = ( - 96F1872EF19E99F8ADD808B1E65B8B69 /* Headers */, - 6940D53F9B60E2FD5D9D3C746E730DE3 /* Sources */, - 1E07408F439DF18F6E00E57E5F98802C /* Frameworks */, - 63C068F9877C73F56D48BE3DB4386199 /* Resources */, + CCA9F09DA21422F28223E467DEA7A70E /* Headers */, + BFECFBB190668E41AF27C75FEFCBF995 /* Sources */, + 93E91658F755D8E6D1B28E734A21DEE6 /* Frameworks */, + 90979D6BE39F3FB1FA5EF9D98F70DD2D /* Resources */, ); buildRules = ( ); @@ -532,39 +501,39 @@ ); name = Interpolate; productName = Interpolate; - productReference = 281F9106CA5C3D6315BCBA75249C7666 /* Interpolate.framework */; + productReference = 0B1BB7463FE6D089000505026AD843BB /* Interpolate.framework */; productType = "com.apple.product-type.framework"; }; 9B2B285779D9F10A469D20EE54DDF71B /* Pods-AGAudioPlayer */ = { isa = PBXNativeTarget; - buildConfigurationList = F7EB8F953E1E50D46B9E1575DA1AA7C4 /* Build configuration list for PBXNativeTarget "Pods-AGAudioPlayer" */; + buildConfigurationList = F0900BAE6E262D7E002C413861E58F4C /* Build configuration list for PBXNativeTarget "Pods-AGAudioPlayer" */; buildPhases = ( - FA42B9CF0EEE685B7404EB9F5C95772B /* Headers */, - FDB5C30547BE7E91BC1F87DD48EE0C04 /* Sources */, - 9443866A531D464BF78A2E54A5D6C471 /* Frameworks */, - A3226F3F41001D46F1340DD4CFF463C3 /* Resources */, + 2600FD8911D8C12E6DD1BAFE88E8AEAD /* Headers */, + FD26CB919D2A5E156B10A66A38B19179 /* Sources */, + 1A6ABFB3F71ADA7F9622DEC9B7A3BDF4 /* Frameworks */, + CD0C09EA550C930E5D77199CBD601984 /* Resources */, ); buildRules = ( ); dependencies = ( - 6DCCF00FA5D52B603E6B8809396A231B /* PBXTargetDependency */, - D15E05B6A851DE23E769C4DB8ECD9B58 /* PBXTargetDependency */, - 46887AC0C50B4EB43272D005C7CC70B4 /* PBXTargetDependency */, - 1032E7A7DA3B13393BBFD63ADF02FEE2 /* PBXTargetDependency */, + 0A1DA742EA78425F9FBE30EF91A6FAD4 /* PBXTargetDependency */, + B44B29CA56228EBA63B3C0B69ABB4CAC /* PBXTargetDependency */, + 528555D055E75F1EAC8AD9DD5560F50A /* PBXTargetDependency */, + 46E263DD0BB3C2C14DD27072866BD32E /* PBXTargetDependency */, ); name = "Pods-AGAudioPlayer"; productName = "Pods-AGAudioPlayer"; - productReference = BBFF6C5262A13A49F9270EE60040F621 /* Pods_AGAudioPlayer.framework */; + productReference = 33C3579C2ED1F40096F11255010EDBB4 /* Pods_AGAudioPlayer.framework */; productType = "com.apple.product-type.framework"; }; C23DB88E45B0ED14F0C8827BE9C46C95 /* MarqueeLabel */ = { isa = PBXNativeTarget; - buildConfigurationList = 56AFAE1E01B62C5B5B86AC4C0B59906C /* Build configuration list for PBXNativeTarget "MarqueeLabel" */; + buildConfigurationList = 25360692F94D05B6B4344D370C7EC6AA /* Build configuration list for PBXNativeTarget "MarqueeLabel" */; buildPhases = ( - 86CC3A1FB762E6717AD4D9C9E004C23F /* Headers */, - 83ACAEA16128AAC30790E10992D09A91 /* Sources */, - 3A9938CAE8D7BC132F6E93FB08A7A3DF /* Frameworks */, - 91460E34655895EEBF238FB1293DE3F2 /* Resources */, + 3076D331E9F18C1C52553382CDD01DA8 /* Headers */, + 8FEEA90DA6EE49996DA2C10407C82C74 /* Sources */, + 4274CA0E731AECC68C24808C7E6703AA /* Frameworks */, + 888A2E430615987F208E1A0B7610045B /* Resources */, ); buildRules = ( ); @@ -572,17 +541,17 @@ ); name = MarqueeLabel; productName = MarqueeLabel; - productReference = 8A3F83AA70224466B9FED21BF4C56F9C /* MarqueeLabel.framework */; + productReference = CF0AA9FBFBDB70858C030769541505ED /* MarqueeLabel.framework */; productType = "com.apple.product-type.framework"; }; E206AE588276C8BCEC39854453B4297C /* BASSGaplessAudioPlayer */ = { isa = PBXNativeTarget; - buildConfigurationList = B403D923D01857746A9A8C223778B354 /* Build configuration list for PBXNativeTarget "BASSGaplessAudioPlayer" */; + buildConfigurationList = 027B31C06EE92B93CEFF79587CDC0674 /* Build configuration list for PBXNativeTarget "BASSGaplessAudioPlayer" */; buildPhases = ( - 1D05B1AA36B0BB296FBCA19D5F9B013D /* Headers */, - 0A3EFB87FB27AB0EF799A5C8A1E5737F /* Sources */, - 149429C2161171E83F28A0C0C2A5A130 /* Frameworks */, - E45EAF8AB74DB3AF6D2666D7BBDFA415 /* Resources */, + 1EB8BF23AF50B6F229D74CBE46E18F31 /* Headers */, + 4039698331D1E3FD9754196E5BE09686 /* Sources */, + 8DA82DD62D7752C9807F448BC1C99039 /* Frameworks */, + C4D28FD593CE86A9B5A76C315F8EBA3D /* Resources */, ); buildRules = ( ); @@ -590,7 +559,7 @@ ); name = BASSGaplessAudioPlayer; productName = BASSGaplessAudioPlayer; - productReference = 6E064C6194985EC358526BF39ABFFBC0 /* BASSGaplessAudioPlayer.framework */; + productReference = 5C6985B0E902290F51F011A7442C1C9C /* BASSGaplessAudioPlayer.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ @@ -599,21 +568,16 @@ BFDFE7DC352907FC980B868725387E98 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 0930; - TargetAttributes = { - 6C7CE3CDC16FE41E5088964C355F522A = { - LastSwiftMigration = 1020; - }; - }; + LastSwiftUpdateCheck = 1100; + LastUpgradeCheck = 1100; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, + Base, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; productRefGroup = 12753F70819F9241988F98EFEC136F0C /* Products */; @@ -630,35 +594,35 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 5C3F6FD505E4E2CE7833601F3BFDA7EB /* Resources */ = { + 888A2E430615987F208E1A0B7610045B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 63C068F9877C73F56D48BE3DB4386199 /* Resources */ = { + 90979D6BE39F3FB1FA5EF9D98F70DD2D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 91460E34655895EEBF238FB1293DE3F2 /* Resources */ = { + C4D28FD593CE86A9B5A76C315F8EBA3D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - A3226F3F41001D46F1340DD4CFF463C3 /* Resources */ = { + CD0C09EA550C930E5D77199CBD601984 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - E45EAF8AB74DB3AF6D2666D7BBDFA415 /* Resources */ = { + FCE454C9441613F1274C3F7EC0725EF0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -668,91 +632,156 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 0A3EFB87FB27AB0EF799A5C8A1E5737F /* Sources */ = { + 4039698331D1E3FD9754196E5BE09686 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A126DF6F537828B8E3AB6AD732E74369 /* BASSGaplessAudioPlayer-dummy.m in Sources */, - 505378D3562F35935EBA2E957C0B15C7 /* ObjectiveBASS.m in Sources */, + 48C84AA27B8C55FFBD1BF37080637F75 /* BASSGaplessAudioPlayer-dummy.m in Sources */, + 15F020BD77E6767B2E1F06FB110CEFC8 /* ObjectiveBASS.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 6940D53F9B60E2FD5D9D3C746E730DE3 /* Sources */ = { + 7F87F5EDC0392A2F640E07C03128E758 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DC909A9574EFE68A74739AEE9CC37C0C /* BasicInterpolation.swift in Sources */, - A821FDE252B0728C61E1B5AFBE1E42F2 /* Interpolatable.swift in Sources */, - 50B0AAD9FB5E4C77E36623A31B927B6D /* Interpolate-dummy.m in Sources */, - 3521D456B138B72A36202F946977A43F /* Interpolate.swift in Sources */, - 0198CA25F234B7889463C862AE27F888 /* SpringInterpolation.swift in Sources */, + 665724D8DCC2E0CFEEF037843846D54E /* NapySlider-dummy.m in Sources */, + 34BDFAD1754BC0D4F83B669C43E9442E /* NapySlider.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 79CBD22146971D2F1C9C7B08943CC118 /* Sources */ = { + 8FEEA90DA6EE49996DA2C10407C82C74 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E719B6F7CAC97346BA0AE8E4E5B500E5 /* NapySlider-dummy.m in Sources */, - 9C420C54006E88A2674418F5A5F83E23 /* NapySlider.swift in Sources */, + ADE8E38AE2FC314562F857E3D97467C4 /* MarqueeLabel-dummy.m in Sources */, + C8BB2EAEB3F03D521DC374327ADD7FE7 /* MarqueeLabel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 83ACAEA16128AAC30790E10992D09A91 /* Sources */ = { + BFECFBB190668E41AF27C75FEFCBF995 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0EC567AB0CFA098BEC23D7B29514ACB0 /* MarqueeLabel-dummy.m in Sources */, - 40AB371EC00736015C6526F9FADA7695 /* MarqueeLabel.m in Sources */, + 26A0AE07E76AD8DE9ED97B151B827617 /* BasicInterpolation.swift in Sources */, + 5788009C2C2DB44FB0FF45A3DB7AB6C6 /* Interpolatable.swift in Sources */, + 20DC980C3816419715B74E552C137410 /* Interpolate-dummy.m in Sources */, + EF865541300D89F9D52951642F6309B8 /* Interpolate.swift in Sources */, + CFE2C3DE4CCDAF6879E25224EE092955 /* SpringInterpolation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - FDB5C30547BE7E91BC1F87DD48EE0C04 /* Sources */ = { + FD26CB919D2A5E156B10A66A38B19179 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 50A5E3272E920B2E569BCEA6D4298C60 /* Pods-AGAudioPlayer-dummy.m in Sources */, + 74EE97E4DED44D7BDF9E87454590D2DD /* Pods-AGAudioPlayer-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 1032E7A7DA3B13393BBFD63ADF02FEE2 /* PBXTargetDependency */ = { + 0A1DA742EA78425F9FBE30EF91A6FAD4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = BASSGaplessAudioPlayer; + target = E206AE588276C8BCEC39854453B4297C /* BASSGaplessAudioPlayer */; + targetProxy = D010C847F1FFBFAC74FB4347F136A64D /* PBXContainerItemProxy */; + }; + 46E263DD0BB3C2C14DD27072866BD32E /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = NapySlider; target = 03AE74D07594E1CB394E8D6D1ACA8180 /* NapySlider */; - targetProxy = 38643B974A16547DA1E86A74C7BB1F7B /* PBXContainerItemProxy */; + targetProxy = 1285A8B5F12BDF35DBB07D9239756E5F /* PBXContainerItemProxy */; }; - 46887AC0C50B4EB43272D005C7CC70B4 /* PBXTargetDependency */ = { + 528555D055E75F1EAC8AD9DD5560F50A /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = MarqueeLabel; target = C23DB88E45B0ED14F0C8827BE9C46C95 /* MarqueeLabel */; - targetProxy = 1F08096FDF3B347E4DA9541CDA53EDD5 /* PBXContainerItemProxy */; - }; - 6DCCF00FA5D52B603E6B8809396A231B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = BASSGaplessAudioPlayer; - target = E206AE588276C8BCEC39854453B4297C /* BASSGaplessAudioPlayer */; - targetProxy = C814F95853A36C1EC026E2D2F9D53466 /* PBXContainerItemProxy */; + targetProxy = 06734A1B4450AE9F3EBDB22DDE45FA76 /* PBXContainerItemProxy */; }; - D15E05B6A851DE23E769C4DB8ECD9B58 /* PBXTargetDependency */ = { + B44B29CA56228EBA63B3C0B69ABB4CAC /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = Interpolate; target = 6C7CE3CDC16FE41E5088964C355F522A /* Interpolate */; - targetProxy = 77AF471CF468A736072DE9D98B621E0C /* PBXContainerItemProxy */; + targetProxy = 9587A777AA42611DC380EF488132EE78 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 08B45F6CBF9ACAD1A4B6FE911C872E0A /* Debug */ = { + 08BF5915DFC43D8FE2EBDF0AF495D9D0 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 83476A1431D492B3CD8299BE591BE5A9 /* Pods-AGAudioPlayer.debug.xcconfig */; + baseConfigurationReference = 893B0F76DBD07C23DD654D2FFCA11852 /* BASSGaplessAudioPlayer.debug.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + 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"; + ENABLE_BITCODE = NO; + GCC_PREFIX_HEADER = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.modulemap"; + PRODUCT_MODULE_NAME = BASSGaplessAudioPlayer; + PRODUCT_NAME = BASSGaplessAudioPlayer; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 1091F99B00434988A97A9528DB6FCF15 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 87CECE363BB082CBA4E652DD3E203207 /* MarqueeLabel.release.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + "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"; + ENABLE_BITCODE = NO; + GCC_PREFIX_HEADER = "Target Support Files/MarqueeLabel/MarqueeLabel-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/MarqueeLabel/MarqueeLabel-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/MarqueeLabel/MarqueeLabel.modulemap"; + PRODUCT_MODULE_NAME = MarqueeLabel; + PRODUCT_NAME = MarqueeLabel; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 1E34A5F487884089770F6FADB5561C45 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1DDF22F3F5B1A336192085BF4E109776 /* Pods-AGAudioPlayer.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -776,17 +805,18 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Debug; + name = Release; }; - 26F21BEB9EC614EDDD64E20629CBFDA9 /* Release */ = { + 22C920631EA194FFCC75E5B5ED96734D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 40F50EE17EE0402B778FA5028B17C460 /* MarqueeLabel.xcconfig */; + baseConfigurationReference = 6046513E6AF129208CF2E6653AD2A694 /* BASSGaplessAudioPlayer.release.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CODE_SIGN_IDENTITY = ""; + CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -796,18 +826,18 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; - GCC_PREFIX_HEADER = "Target Support Files/MarqueeLabel/MarqueeLabel-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/MarqueeLabel/MarqueeLabel-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/MarqueeLabel/MarqueeLabel.modulemap"; - PRODUCT_MODULE_NAME = MarqueeLabel; - PRODUCT_NAME = MarqueeLabel; + MODULEMAP_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.modulemap"; + PRODUCT_MODULE_NAME = BASSGaplessAudioPlayer; + PRODUCT_NAME = BASSGaplessAudioPlayer; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -815,12 +845,11 @@ }; name = Release; }; - 4A9D35D264C907493753DE360C3DA944 /* Debug */ = { + 44A65628B1B936DADAE12BEF12EFC88B /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 40F50EE17EE0402B778FA5028B17C460 /* MarqueeLabel.xcconfig */; + baseConfigurationReference = 83CEE7933A3D4ACA37EB0154538D5EEB /* Interpolate.release.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -830,28 +859,30 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; - GCC_PREFIX_HEADER = "Target Support Files/MarqueeLabel/MarqueeLabel-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/MarqueeLabel/MarqueeLabel-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/Interpolate/Interpolate-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Interpolate/Interpolate-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/MarqueeLabel/MarqueeLabel.modulemap"; - PRODUCT_MODULE_NAME = MarqueeLabel; - PRODUCT_NAME = MarqueeLabel; + MODULEMAP_FILE = "Target Support Files/Interpolate/Interpolate.modulemap"; + PRODUCT_MODULE_NAME = Interpolate; + PRODUCT_NAME = Interpolate; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Debug; + name = Release; }; - 4CE281642D6EE9FAB113046B4B6328A0 /* Release */ = { + 903A0004D3E6651EFD5D2E16214D101B /* 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"; @@ -874,6 +905,7 @@ 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; @@ -901,52 +933,20 @@ MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.2; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; SYMROOT = "${SRCROOT}/../build"; }; name = Release; }; - 55A0C6DFE2D1A68F0A01B93C37BD7D69 /* Debug */ = { + 9E7C13476BE419DB959552590310DBB6 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 82FB224B257650A87831517C474E7E85 /* NapySlider.xcconfig */; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CODE_SIGN_IDENTITY = ""; - "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"; - ENABLE_BITCODE = NO; - GCC_PREFIX_HEADER = "Target Support Files/NapySlider/NapySlider-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/NapySlider/NapySlider-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.4; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/NapySlider/NapySlider.modulemap"; - PRODUCT_MODULE_NAME = NapySlider; - PRODUCT_NAME = NapySlider; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 5FBBFC7E00D017F5B61C49473426879B /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = A0AE4A6ED8711F57E92E2F21A8217EB3 /* BASSGaplessAudioPlayer.xcconfig */; + baseConfigurationReference = 83476A1431D492B3CD8299BE591BE5A9 /* Pods-AGAudioPlayer.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -956,29 +956,30 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; - GCC_PREFIX_HEADER = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-Info.plist"; + INFOPLIST_FILE = "Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.modulemap"; - PRODUCT_MODULE_NAME = BASSGaplessAudioPlayer; - PRODUCT_NAME = BASSGaplessAudioPlayer; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.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; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Release; + name = Debug; }; - 6DFA1578582149B7E24AD55CBA30F07A /* Debug */ = { + B4EFE046ACF8F37157F6E322C7FCFC28 /* 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"; @@ -1001,6 +1002,7 @@ 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; @@ -1034,18 +1036,16 @@ STRIP_INSTALLED_PRODUCT = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; SYMROOT = "${SRCROOT}/../build"; }; name = Debug; }; - 97B5EC4BBE602A878784C614346FC592 /* Debug */ = { + DDD9E4752D67B7ECE4A52C9D52863B0F /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A0AE4A6ED8711F57E92E2F21A8217EB3 /* BASSGaplessAudioPlayer.xcconfig */; + baseConfigurationReference = 46D29586B4DF93D02D94CC778DD31C8E /* MarqueeLabel.debug.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1055,14 +1055,14 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; - GCC_PREFIX_HEADER = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/MarqueeLabel/MarqueeLabel-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/MarqueeLabel/MarqueeLabel-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"; - MODULEMAP_FILE = "Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.modulemap"; - PRODUCT_MODULE_NAME = BASSGaplessAudioPlayer; - PRODUCT_NAME = BASSGaplessAudioPlayer; + MODULEMAP_FILE = "Target Support Files/MarqueeLabel/MarqueeLabel.modulemap"; + PRODUCT_MODULE_NAME = MarqueeLabel; + PRODUCT_NAME = MarqueeLabel; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; @@ -1073,12 +1073,11 @@ }; name = Debug; }; - 9D0BB60E72891BEE7B01B5B4EB9EC577 /* Debug */ = { + DE0A84939A3AD81726C2782F6A374090 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5769BA40B0151D47D2E70FA0ED7306A5 /* Interpolate.xcconfig */; + baseConfigurationReference = E4BB5851DD44B4185DBB94A2F1A93085 /* Interpolate.debug.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1099,19 +1098,18 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; - A5358BB7BF4273C3311462F432BDEDFD /* Release */ = { + E50AA0CFC5DF77761F7E6571E823560C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5769BA40B0151D47D2E70FA0ED7306A5 /* Interpolate.xcconfig */; + baseConfigurationReference = 90F5F1165D9AB46DAA4B2C8A3B97E39C /* NapySlider.debug.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1121,31 +1119,29 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; - GCC_PREFIX_HEADER = "Target Support Files/Interpolate/Interpolate-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/Interpolate/Interpolate-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/NapySlider/NapySlider-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/NapySlider/NapySlider-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/Interpolate/Interpolate.modulemap"; - PRODUCT_MODULE_NAME = Interpolate; - PRODUCT_NAME = Interpolate; + MODULEMAP_FILE = "Target Support Files/NapySlider/NapySlider.modulemap"; + PRODUCT_MODULE_NAME = NapySlider; + PRODUCT_NAME = NapySlider; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Release; + name = Debug; }; - D34504ADEC9837FE3F31ECE46D143819 /* Release */ = { + F5F65F26DDF5428F9C13552C05BCEFAC /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 82FB224B257650A87831517C474E7E85 /* NapySlider.xcconfig */; + baseConfigurationReference = 68860F76C7921C9D53C1D5C9163E2021 /* NapySlider.release.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1174,96 +1170,59 @@ }; name = Release; }; - D482E708B9838ED889EDB1DE43482E4F /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 1DDF22F3F5B1A336192085BF4E109776 /* Pods-AGAudioPlayer.release.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_ENABLE_OBJC_WEAK = NO; - CODE_SIGN_IDENTITY = ""; - "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"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = "Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACH_O_TYPE = staticlib; - MODULEMAP_FILE = "Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.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; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + 027B31C06EE92B93CEFF79587CDC0674 /* Build configuration list for PBXNativeTarget "BASSGaplessAudioPlayer" */ = { isa = XCConfigurationList; buildConfigurations = ( - 6DFA1578582149B7E24AD55CBA30F07A /* Debug */, - 4CE281642D6EE9FAB113046B4B6328A0 /* Release */, + 08BF5915DFC43D8FE2EBDF0AF495D9D0 /* Debug */, + 22C920631EA194FFCC75E5B5ED96734D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 56AFAE1E01B62C5B5B86AC4C0B59906C /* Build configuration list for PBXNativeTarget "MarqueeLabel" */ = { + 25360692F94D05B6B4344D370C7EC6AA /* Build configuration list for PBXNativeTarget "MarqueeLabel" */ = { isa = XCConfigurationList; buildConfigurations = ( - 4A9D35D264C907493753DE360C3DA944 /* Debug */, - 26F21BEB9EC614EDDD64E20629CBFDA9 /* Release */, + DDD9E4752D67B7ECE4A52C9D52863B0F /* Debug */, + 1091F99B00434988A97A9528DB6FCF15 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 9E4D50409F9E1005883EB1206C75358E /* Build configuration list for PBXNativeTarget "Interpolate" */ = { + 310EDBA21EC772085F3F2830790BD8B2 /* Build configuration list for PBXNativeTarget "NapySlider" */ = { isa = XCConfigurationList; buildConfigurations = ( - 9D0BB60E72891BEE7B01B5B4EB9EC577 /* Debug */, - A5358BB7BF4273C3311462F432BDEDFD /* Release */, + E50AA0CFC5DF77761F7E6571E823560C /* Debug */, + F5F65F26DDF5428F9C13552C05BCEFAC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - B403D923D01857746A9A8C223778B354 /* Build configuration list for PBXNativeTarget "BASSGaplessAudioPlayer" */ = { + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( - 97B5EC4BBE602A878784C614346FC592 /* Debug */, - 5FBBFC7E00D017F5B61C49473426879B /* Release */, + B4EFE046ACF8F37157F6E322C7FCFC28 /* Debug */, + 903A0004D3E6651EFD5D2E16214D101B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F6B4F85B5375EB04FF9BA518A261EA94 /* Build configuration list for PBXNativeTarget "NapySlider" */ = { + 89B1E22E78BDFFE5567B05422CC73C33 /* Build configuration list for PBXNativeTarget "Interpolate" */ = { isa = XCConfigurationList; buildConfigurations = ( - 55A0C6DFE2D1A68F0A01B93C37BD7D69 /* Debug */, - D34504ADEC9837FE3F31ECE46D143819 /* Release */, + DE0A84939A3AD81726C2782F6A374090 /* Debug */, + 44A65628B1B936DADAE12BEF12EFC88B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F7EB8F953E1E50D46B9E1575DA1AA7C4 /* Build configuration list for PBXNativeTarget "Pods-AGAudioPlayer" */ = { + F0900BAE6E262D7E002C413861E58F4C /* Build configuration list for PBXNativeTarget "Pods-AGAudioPlayer" */ = { isa = XCConfigurationList; buildConfigurations = ( - 08B45F6CBF9ACAD1A4B6FE911C872E0A /* Debug */, - D482E708B9838ED889EDB1DE43482E4F /* Release */, + 9E7C13476BE419DB959552590310DBB6 /* Debug */, + 1E34A5F487884089770F6FADB5561C45 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.debug.xcconfig b/Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.debug.xcconfig new file mode 100644 index 0000000..89366e6 --- /dev/null +++ b/Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BASSGaplessAudioPlayer +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/../../gapless-audio-bass-ios/BASS Audio Test" +OTHER_LDFLAGS = $(inherited) -l"bass" -l"bass_fx" -l"bassmix" -l"stdc++" -framework "AVFoundation" -framework "Accelerate" -framework "AudioToolbox" -framework "CFNetwork" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../gapless-audio-bass-ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.release.xcconfig b/Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.release.xcconfig new file mode 100644 index 0000000..89366e6 --- /dev/null +++ b/Pods/Target Support Files/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BASSGaplessAudioPlayer +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/../../gapless-audio-bass-ios/BASS Audio Test" +OTHER_LDFLAGS = $(inherited) -l"bass" -l"bass_fx" -l"bassmix" -l"stdc++" -framework "AVFoundation" -framework "Accelerate" -framework "AudioToolbox" -framework "CFNetwork" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../gapless-audio-bass-ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Interpolate/Interpolate-Info.plist b/Pods/Target Support Files/Interpolate/Interpolate-Info.plist index 19f73ea..b6b2813 100644 --- a/Pods/Target Support Files/Interpolate/Interpolate-Info.plist +++ b/Pods/Target Support Files/Interpolate/Interpolate-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.2.1 + 1.3.0 CFBundleSignature ???? CFBundleVersion diff --git a/Pods/Target Support Files/Interpolate/Interpolate.debug.xcconfig b/Pods/Target Support Files/Interpolate/Interpolate.debug.xcconfig new file mode 100644 index 0000000..651ca58 --- /dev/null +++ b/Pods/Target Support Files/Interpolate/Interpolate.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Interpolate +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "QuartzCore" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Interpolate +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Interpolate/Interpolate.release.xcconfig b/Pods/Target Support Files/Interpolate/Interpolate.release.xcconfig new file mode 100644 index 0000000..651ca58 --- /dev/null +++ b/Pods/Target Support Files/Interpolate/Interpolate.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Interpolate +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "QuartzCore" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Interpolate +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-Info.plist b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-Info.plist index 42c9fae..aebe579 100644 --- a/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-Info.plist +++ b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 3.2.1 + 4.0.5 CFBundleSignature ???? CFBundleVersion diff --git a/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-umbrella.h b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-umbrella.h index 0710b61..31487a3 100644 --- a/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-umbrella.h +++ b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel-umbrella.h @@ -10,7 +10,6 @@ #endif #endif -#import "MarqueeLabel.h" FOUNDATION_EXPORT double MarqueeLabelVersionNumber; FOUNDATION_EXPORT const unsigned char MarqueeLabelVersionString[]; diff --git a/Pods/Target Support Files/MarqueeLabel/MarqueeLabel.debug.xcconfig b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel.debug.xcconfig new file mode 100644 index 0000000..de1897d --- /dev/null +++ b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "QuartzCore" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MarqueeLabel +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/MarqueeLabel/MarqueeLabel.release.xcconfig b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel.release.xcconfig new file mode 100644 index 0000000..de1897d --- /dev/null +++ b/Pods/Target Support Files/MarqueeLabel/MarqueeLabel.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "QuartzCore" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MarqueeLabel +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/NapySlider/NapySlider.debug.xcconfig b/Pods/Target Support Files/NapySlider/NapySlider.debug.xcconfig new file mode 100644 index 0000000..b18150f --- /dev/null +++ b/Pods/Target Support Files/NapySlider/NapySlider.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/NapySlider +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/NapySlider +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/NapySlider/NapySlider.release.xcconfig b/Pods/Target Support Files/NapySlider/NapySlider.release.xcconfig new file mode 100644 index 0000000..b18150f --- /dev/null +++ b/Pods/Target Support Files/NapySlider/NapySlider.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/NapySlider +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/NapySlider +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer-frameworks.sh b/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer-frameworks.sh index 8b2033e..2686c40 100755 --- a/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer-frameworks.sh +++ b/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer-frameworks.sh @@ -19,9 +19,8 @@ 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" -# Used as a return value for each invocation of `strip_invalid_archs` function. -STRIP_BINARY_RETVAL=0 # 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 @@ -45,9 +44,19 @@ install_framework() 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[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" - rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + 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")" @@ -80,69 +89,52 @@ install_framework() 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 a the targets temp dir. + # 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 .framework.dSYM "$source")" - binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${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 so "fat" simulator / device frameworks work on device - if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then - strip_invalid_archs "$binary" + # 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 == 1 ]]; then + if [[ $STRIP_BINARY_RETVAL == 0 ]]; then # Move the stripped file into its final destination. - echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --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[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + 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}.framework.dSYM" + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" fi fi } -# Copies the bcsymbolmap files of a vendored framework -install_bcsymbolmap() { - local bcsymbolmap_path = "$1" - local destination="${TARGET_BUILD_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 -} +# 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 - echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." - STRIP_BINARY_RETVAL=0 + 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="" @@ -156,9 +148,31 @@ strip_invalid_archs() { if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi - STRIP_BINARY_RETVAL=1 + 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}/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.framework" diff --git a/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.debug.xcconfig b/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.debug.xcconfig index 3108683..5235569 100644 --- a/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.debug.xcconfig +++ b/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.debug.xcconfig @@ -1,4 +1,5 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BASSGaplessAudioPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/Interpolate" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "${PODS_CONFIGURATION_BUILD_DIR}/NapySlider" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Interpolate/Interpolate.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel/MarqueeLabel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/NapySlider/NapySlider.framework/Headers" @@ -11,3 +12,5 @@ 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/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.release.xcconfig b/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.release.xcconfig index 3108683..5235569 100644 --- a/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.release.xcconfig +++ b/Pods/Target Support Files/Pods-AGAudioPlayer/Pods-AGAudioPlayer.release.xcconfig @@ -1,4 +1,5 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BASSGaplessAudioPlayer" "${PODS_CONFIGURATION_BUILD_DIR}/Interpolate" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "${PODS_CONFIGURATION_BUILD_DIR}/NapySlider" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BASSGaplessAudioPlayer/BASSGaplessAudioPlayer.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Interpolate/Interpolate.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel/MarqueeLabel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/NapySlider/NapySlider.framework/Headers" @@ -11,3 +12,5 @@ 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