├── CODEOWNERS ├── .gitignore ├── Package.swift ├── Fingertips.podspec ├── Fingertips.xcodeproj ├── Info.plist ├── xcshareddata │ └── xcschemes │ │ └── Fingertips.xcscheme └── project.pbxproj ├── LICENSE.md ├── README.md └── Sources └── Fingertips └── FingerTipWindow.swift /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @OdNairy 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | README-VENDOR-BRANCH.txt 2 | 3 | # Xcode 4 | build/* 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | *.xcworkspace 14 | !default.xcworkspace 15 | xcuserdata 16 | profile 17 | *.moved-aside 18 | 19 | Carthage/Build 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "Fingertips", 6 | platforms: [.iOS(.v11)], 7 | products: [ 8 | .library(name: "Fingertips", targets: ["Fingertips"]), 9 | ], 10 | targets: [ 11 | .target( 12 | name: "Fingertips", 13 | dependencies: [], 14 | publicHeadersPath: ".") 15 | ] 16 | ) 17 | -------------------------------------------------------------------------------- /Fingertips.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |f| 2 | 3 | f.name = 'Fingertips' 4 | f.version = '0.6.0' 5 | 6 | f.summary = 'Touch indicators on external displays for iOS applications.' 7 | f.description = 'Touch indicators on external displays for iOS applications, giving you automatic presentation mode using a simple UIWindow subclass.' 8 | f.homepage = 'https://github.com/mapbox/Fingertips' 9 | f.license = 'BSD' 10 | f.author = { 'Mapbox' => 'mobile@mapbox.com' } 11 | f.social_media_url = 'https://twitter.com/Mapbox' 12 | 13 | f.source = { :git => 'https://github.com/mapbox/Fingertips.git', :tag => "v#{f.version.to_s}" } 14 | 15 | f.platform = :ios, '11.0' 16 | 17 | f.source_files = 'Sources/Fingertips/*.{swift}' 18 | 19 | f.swift_version = '5' 20 | 21 | f.framework = 'UIKit' 22 | 23 | end 24 | -------------------------------------------------------------------------------- /Fingertips.xcodeproj/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2013, Mapbox, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | * Neither the name of MapBox, Inc., nor the names of its contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Fingertips.xcodeproj/xcshareddata/xcschemes/Fingertips.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fingertips 2 | 3 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2FFingertips.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2FFingertips?ref=badge_shield) 4 | 5 | ## Presentation mode for your iOS app 6 | 7 | Fingertips is a small library (one class) meant for presentations from iOS devices that shows all touches and gestures so that the audience can see them. 8 | 9 | **This library does not do the mirroring or screen recording for you!** 10 | 11 | Just drop in our replacement `UIWindow` subclass and your app will automatically determine when you are in the screen recording or an external screen is available. It will show every touch on-screen with a nice partially-transparent graphic that automatically fades out when the touch ends. 12 | 13 | If you are using storyboards, the easiest way to integrate Fingertips is to override the `window` method of your application delegate like this: 14 | 15 | ```objc 16 | // AppDelegate.m 17 | 18 | - (UIWindow *)window { 19 | if (!_window) { 20 | _window = [[MBFingerTipWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 21 | } 22 | return _window; 23 | } 24 | ``` 25 | 26 | ```swift 27 | // AppDelegate.swift (Swift) 28 | 29 | var window: UIWindow? = FingerTipWindow(frame: UIScreen.main.bounds) 30 | ``` 31 | 32 | For iOS 13+ with UISceneDelegate: 33 | 34 | ```swift 35 | var windows: [UIWindow] = [] 36 | 37 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 38 | guard let windowScene = scene as? UIWindowScene else { return } 39 | 40 | let window = FingerTipWindow(windowScene: windowScene) 41 | 42 | window.rootViewController = // Your root view controller 43 | window.makeKeyAndVisible() 44 | 45 | windows.append(window) 46 | } 47 | 48 | ``` 49 | 50 | Fingertips require iOS 11.0 or greater and ARC. It uses **no private API** and is safe for App Store submissions. 51 | 52 | https://github.com/mapbox/Fingertips/assets/735178/833f659e-b549-4e74-ae27-e695f37717b6 53 | 54 | ## Configuration 55 | 56 | You shouldn't need to configure anything, but if you want to tweak some knobs: 57 | 58 | * `touchImage`: pass a `UIImage` to use for showing touches 59 | * `touchAlpha`: change the visible-touch alpha transparency 60 | * `fadeDuration`: change how long lifted touches fade out 61 | * `strokeColor`: change default `touchImage` stroke color (defaults to black) 62 | * `fillColor`: change default `touchImage` fill color (defaults to white) 63 | 64 | If you ever need to debug Fingertips, just set the `DEBUG_FINGERTIP_WINDOW` environment variable to `YES` in Xcode or set the runtime property `alwaysShowTouches` to `YES`. 65 | 66 | ## License 67 | 68 | Copyright (c) 2011-2023 Mapbox, Inc. 69 | 70 | The Fingertips library should be accompanied by a LICENSE file. This file contains the license relevant to this distribution. If no license exists, please contact [Mapbox](http://mapbox.com). 71 | 72 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2FFingertips.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2FFingertips?ref=badge_large) 73 | -------------------------------------------------------------------------------- /Sources/Fingertips/FingerTipWindow.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2011-2023 Mapbox, Inc. All rights reserved. 2 | 3 | import Foundation 4 | import UIKit 5 | 6 | @objc(MBXFingerTipView) 7 | class FingerTipView: UIImageView { 8 | var timestamp: TimeInterval? 9 | var shouldAutomaticallyRemoveAfterTimeout: Bool? 10 | var fadingOut: Bool = false 11 | } 12 | 13 | @objc (MBXFingerTipOverlayWindow) 14 | class FingerTipOverlayWindow: UIWindow {} 15 | 16 | @objc (MBXFingerTipWindow) 17 | open class FingerTipWindow: UIWindow { 18 | 19 | public static var fingerTipWindow: FingerTipWindow? { 20 | return UIApplication.shared.windows.compactMap({ $0 as? FingerTipWindow }).first 21 | } 22 | 23 | public var touchAlpha: CGFloat = 0.5 24 | public var fadeDuration: TimeInterval = 0.3 25 | public var strokeColor: UIColor = .black 26 | public var fillColor: UIColor = .white 27 | 28 | private var active: Bool = false 29 | 30 | /// Force touch display when no external screen is connected or no video recording is going 31 | public var alwaysShowTouches: Bool = false { 32 | didSet { 33 | if oldValue != alwaysShowTouches { 34 | updateFingertipsAreActive() 35 | } 36 | } 37 | } 38 | 39 | lazy var touchImage: UIImage = { 40 | let clipPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 50, height: 50)) 41 | 42 | UIGraphicsBeginImageContextWithOptions(clipPath.bounds.size, false, 0) 43 | defer { UIGraphicsEndImageContext() } 44 | 45 | let drawPath = UIBezierPath(arcCenter: CGPoint(x: 25, y: 25), radius: 22, startAngle: 0, endAngle: 2 * .pi, clockwise: true) 46 | drawPath.lineWidth = 2 47 | 48 | strokeColor.setStroke() 49 | fillColor.setFill() 50 | 51 | drawPath.stroke() 52 | drawPath.fill() 53 | 54 | clipPath.addClip() 55 | 56 | return UIGraphicsGetImageFromCurrentImageContext()! 57 | }() 58 | 59 | private var overlayView: UIView { 60 | return overlayWindow.rootViewController!.view 61 | } 62 | 63 | lazy var overlayWindow: UIWindow = { 64 | let window: UIWindow 65 | if #available(iOS 13.0, *), let windowScene = windowScene { 66 | window = FingerTipOverlayWindow(windowScene: windowScene) 67 | } else { 68 | window = FingerTipOverlayWindow(frame: frame) 69 | } 70 | window.rootViewController = UIViewController() 71 | window.isUserInteractionEnabled = false 72 | window.windowLevel = .statusBar 73 | window.backgroundColor = .clear 74 | window.isHidden = false 75 | return window 76 | }() 77 | 78 | var fingerTipRemovalScheduled: Bool = false 79 | 80 | required public init?(coder aDecoder: NSCoder) { 81 | super.init(coder: aDecoder) 82 | 83 | commonInit() 84 | } 85 | 86 | override public init(frame: CGRect) { 87 | super.init(frame: frame) 88 | 89 | commonInit() 90 | } 91 | 92 | @available(iOS 13.0, *) 93 | public override init(windowScene: UIWindowScene) { 94 | super.init(windowScene: windowScene) 95 | 96 | commonInit() 97 | } 98 | 99 | func commonInit() { 100 | NotificationCenter.default.addObserver(self, selector: #selector(updateFingertipsAreActive), name: UIScreen.didConnectNotification, object: nil) 101 | NotificationCenter.default.addObserver(self, selector: #selector(updateFingertipsAreActive), name: UIScreen.didDisconnectNotification, object: nil) 102 | NotificationCenter.default.addObserver(self, selector: #selector(updateFingertipsAreActive), name: UIScreen.capturedDidChangeNotification, object: nil) 103 | 104 | updateFingertipsAreActive() 105 | } 106 | 107 | func anyScreenIsCaptured() -> Bool { 108 | UIScreen.screens.contains(where: \.isCaptured) 109 | } 110 | 111 | @objc func updateFingertipsAreActive() { 112 | let envDebug = (ProcessInfo.processInfo.environment["DEBUG_FINGERTIP_WINDOW"] as? NSString)?.boolValue 113 | 114 | if alwaysShowTouches || envDebug == true { 115 | active = true 116 | } else { 117 | active = anyScreenIsCaptured() 118 | } 119 | } 120 | 121 | public override func sendEvent(_ event: UIEvent) { 122 | defer { 123 | super.sendEvent(event) 124 | scheduleFingerTipRemoval() 125 | } 126 | 127 | guard active else { return } 128 | 129 | guard let allTouches: Set = event.allTouches else { return } 130 | 131 | for touch in allTouches { 132 | switch touch.phase { 133 | case .began, .moved, .stationary: 134 | var touchView = overlayView.viewWithTag(touch.hashValue) as? FingerTipView 135 | 136 | if touch.phase != .stationary && touchView != nil && touchView?.fadingOut == true { 137 | touchView?.removeFromSuperview() 138 | touchView = nil 139 | } 140 | 141 | if touchView == nil && touch.phase != .stationary { 142 | touchView = FingerTipView(image: touchImage) 143 | touchView?.translatesAutoresizingMaskIntoConstraints = false 144 | overlayView.addSubview(touchView!) 145 | } 146 | 147 | if touchView?.fadingOut == false { 148 | touchView?.alpha = touchAlpha 149 | touchView?.center = touch.location(in: overlayView) 150 | touchView?.tag = touch.hashValue 151 | touchView?.timestamp = touch.timestamp 152 | touchView?.shouldAutomaticallyRemoveAfterTimeout = shouldAutomaticallyRemoveFingerTip(for: touch) 153 | } 154 | 155 | case .ended, .cancelled: 156 | removeFingerTip(with: touch.hashValue, animated: true) 157 | 158 | case .regionEntered, .regionMoved, .regionExited: 159 | fallthrough 160 | 161 | @unknown default: 162 | break 163 | } 164 | } 165 | } 166 | 167 | func scheduleFingerTipRemoval() { 168 | if fingerTipRemovalScheduled { 169 | return 170 | } 171 | 172 | fingerTipRemovalScheduled = true 173 | perform(#selector(removeInactiveFingerTips), with: nil, afterDelay: 0.1) 174 | } 175 | 176 | @objc func removeInactiveFingerTips() { 177 | fingerTipRemovalScheduled = false 178 | 179 | let now = ProcessInfo.processInfo.systemUptime 180 | let REMOVAL_DELAY = 0.2 181 | 182 | for case let touchView as FingerTipView in overlayView.subviews { 183 | if touchView.shouldAutomaticallyRemoveAfterTimeout == true && now > touchView.timestamp ?? 0 + REMOVAL_DELAY { 184 | removeFingerTip(with: touchView.tag, animated: true) 185 | } 186 | } 187 | 188 | if overlayView.subviews.count > 0 { 189 | scheduleFingerTipRemoval() 190 | } 191 | } 192 | 193 | func removeFingerTip(with hash: Int, animated: Bool) { 194 | guard let touchView = overlayView.viewWithTag(hash) as? FingerTipView, !touchView.fadingOut else { return } 195 | 196 | UIView.animate(withDuration: animated ? fadeDuration : 0) { 197 | touchView.fadingOut = true 198 | touchView.alpha = 0 199 | touchView.frame = CGRect(x: touchView.center.x - touchView.frame.size.width / 1.5, 200 | y: touchView.center.y - touchView.frame.size.height / 1.5, 201 | width: touchView.frame.size.width * 1.5, 202 | height: touchView.frame.size.height * 1.5) 203 | 204 | } completion: { _ in 205 | touchView.fadingOut = false 206 | touchView.removeFromSuperview() 207 | } 208 | } 209 | 210 | func shouldAutomaticallyRemoveFingerTip(for touch: UITouch) -> Bool { 211 | var view = touch.view 212 | view = view?.hitTest(touch.location(in: view), with: nil) 213 | 214 | while view != nil { 215 | switch view { 216 | case is UITableViewCell: 217 | for recognizer in touch.gestureRecognizers ?? [] { 218 | if recognizer is UISwipeGestureRecognizer { 219 | return true 220 | } 221 | } 222 | case is UITableView: 223 | if touch.gestureRecognizers?.count == 0 { 224 | return true 225 | } 226 | default: break 227 | } 228 | 229 | view = view?.superview 230 | } 231 | 232 | return false 233 | } 234 | } 235 | 236 | -------------------------------------------------------------------------------- /Fingertips.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 53; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FE228303298419FD000F6CF4 /* FingerTipWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE228302298419FD000F6CF4 /* FingerTipWindow.swift */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXFileReference section */ 14 | BE6B26161CFA17AF001BFB6F /* Fingertips.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Fingertips.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 15 | BE6B261B1CFA17AF001BFB6F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Fingertips.xcodeproj/Info.plist; sourceTree = ""; }; 16 | FE228302298419FD000F6CF4 /* FingerTipWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FingerTipWindow.swift; path = Sources/Fingertips/FingerTipWindow.swift; sourceTree = ""; }; 17 | /* End PBXFileReference section */ 18 | 19 | /* Begin PBXFrameworksBuildPhase section */ 20 | BE6B26121CFA17AF001BFB6F /* Frameworks */ = { 21 | isa = PBXFrameworksBuildPhase; 22 | buildActionMask = 2147483647; 23 | files = ( 24 | ); 25 | runOnlyForDeploymentPostprocessing = 0; 26 | }; 27 | /* End PBXFrameworksBuildPhase section */ 28 | 29 | /* Begin PBXGroup section */ 30 | BE6B260C1CFA17AF001BFB6F = { 31 | isa = PBXGroup; 32 | children = ( 33 | BE6B26181CFA17AF001BFB6F /* Fingertips */, 34 | BE6B26171CFA17AF001BFB6F /* Products */, 35 | ); 36 | sourceTree = ""; 37 | }; 38 | BE6B26171CFA17AF001BFB6F /* Products */ = { 39 | isa = PBXGroup; 40 | children = ( 41 | BE6B26161CFA17AF001BFB6F /* Fingertips.framework */, 42 | ); 43 | name = Products; 44 | sourceTree = ""; 45 | }; 46 | BE6B26181CFA17AF001BFB6F /* Fingertips */ = { 47 | isa = PBXGroup; 48 | children = ( 49 | FE228302298419FD000F6CF4 /* FingerTipWindow.swift */, 50 | BE6B261B1CFA17AF001BFB6F /* Info.plist */, 51 | ); 52 | name = Fingertips; 53 | sourceTree = ""; 54 | }; 55 | /* End PBXGroup section */ 56 | 57 | /* Begin PBXHeadersBuildPhase section */ 58 | BE6B26131CFA17AF001BFB6F /* Headers */ = { 59 | isa = PBXHeadersBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXHeadersBuildPhase section */ 66 | 67 | /* Begin PBXNativeTarget section */ 68 | BE6B26151CFA17AF001BFB6F /* Fingertips */ = { 69 | isa = PBXNativeTarget; 70 | buildConfigurationList = BE6B261E1CFA17AF001BFB6F /* Build configuration list for PBXNativeTarget "Fingertips" */; 71 | buildPhases = ( 72 | BE6B26111CFA17AF001BFB6F /* Sources */, 73 | BE6B26121CFA17AF001BFB6F /* Frameworks */, 74 | BE6B26131CFA17AF001BFB6F /* Headers */, 75 | BE6B26141CFA17AF001BFB6F /* Resources */, 76 | ); 77 | buildRules = ( 78 | ); 79 | dependencies = ( 80 | ); 81 | name = Fingertips; 82 | productName = Fingertips; 83 | productReference = BE6B26161CFA17AF001BFB6F /* Fingertips.framework */; 84 | productType = "com.apple.product-type.framework"; 85 | }; 86 | /* End PBXNativeTarget section */ 87 | 88 | /* Begin PBXProject section */ 89 | BE6B260D1CFA17AF001BFB6F /* Project object */ = { 90 | isa = PBXProject; 91 | attributes = { 92 | BuildIndependentTargetsInParallel = YES; 93 | LastUpgradeCheck = 1430; 94 | ORGANIZATIONNAME = Mapbox; 95 | TargetAttributes = { 96 | BE6B26151CFA17AF001BFB6F = { 97 | CreatedOnToolsVersion = 7.3.1; 98 | LastSwiftMigration = 1420; 99 | }; 100 | }; 101 | }; 102 | buildConfigurationList = BE6B26101CFA17AF001BFB6F /* Build configuration list for PBXProject "Fingertips" */; 103 | compatibilityVersion = "Xcode 3.2"; 104 | developmentRegion = en; 105 | hasScannedForEncodings = 0; 106 | knownRegions = ( 107 | en, 108 | Base, 109 | ); 110 | mainGroup = BE6B260C1CFA17AF001BFB6F; 111 | productRefGroup = BE6B26171CFA17AF001BFB6F /* Products */; 112 | projectDirPath = ""; 113 | projectRoot = ""; 114 | targets = ( 115 | BE6B26151CFA17AF001BFB6F /* Fingertips */, 116 | ); 117 | }; 118 | /* End PBXProject section */ 119 | 120 | /* Begin PBXResourcesBuildPhase section */ 121 | BE6B26141CFA17AF001BFB6F /* Resources */ = { 122 | isa = PBXResourcesBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | ); 126 | runOnlyForDeploymentPostprocessing = 0; 127 | }; 128 | /* End PBXResourcesBuildPhase section */ 129 | 130 | /* Begin PBXSourcesBuildPhase section */ 131 | BE6B26111CFA17AF001BFB6F /* Sources */ = { 132 | isa = PBXSourcesBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | FE228303298419FD000F6CF4 /* FingerTipWindow.swift in Sources */, 136 | ); 137 | runOnlyForDeploymentPostprocessing = 0; 138 | }; 139 | /* End PBXSourcesBuildPhase section */ 140 | 141 | /* Begin XCBuildConfiguration section */ 142 | BE6B261C1CFA17AF001BFB6F /* Debug */ = { 143 | isa = XCBuildConfiguration; 144 | buildSettings = { 145 | ALWAYS_SEARCH_USER_PATHS = NO; 146 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 147 | CLANG_ANALYZER_NONNULL = YES; 148 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 149 | CLANG_CXX_LIBRARY = "libc++"; 150 | CLANG_ENABLE_MODULES = YES; 151 | CLANG_ENABLE_OBJC_ARC = YES; 152 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 153 | CLANG_WARN_BOOL_CONVERSION = YES; 154 | CLANG_WARN_COMMA = YES; 155 | CLANG_WARN_CONSTANT_CONVERSION = YES; 156 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 157 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 158 | CLANG_WARN_EMPTY_BODY = YES; 159 | CLANG_WARN_ENUM_CONVERSION = YES; 160 | CLANG_WARN_INFINITE_RECURSION = YES; 161 | CLANG_WARN_INT_CONVERSION = YES; 162 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 163 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 164 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 165 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 166 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 167 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 168 | CLANG_WARN_STRICT_PROTOTYPES = YES; 169 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 170 | CLANG_WARN_UNREACHABLE_CODE = YES; 171 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 172 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 173 | CURRENT_PROJECT_VERSION = 1; 174 | DEBUG_INFORMATION_FORMAT = dwarf; 175 | ENABLE_STRICT_OBJC_MSGSEND = YES; 176 | ENABLE_TESTABILITY = YES; 177 | GCC_C_LANGUAGE_STANDARD = gnu99; 178 | GCC_DYNAMIC_NO_PIC = NO; 179 | GCC_NO_COMMON_BLOCKS = YES; 180 | GCC_OPTIMIZATION_LEVEL = 0; 181 | GCC_PREPROCESSOR_DEFINITIONS = ( 182 | "DEBUG=1", 183 | "$(inherited)", 184 | ); 185 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 186 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 187 | GCC_WARN_UNDECLARED_SELECTOR = YES; 188 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 189 | GCC_WARN_UNUSED_FUNCTION = YES; 190 | GCC_WARN_UNUSED_VARIABLE = YES; 191 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 192 | MTL_ENABLE_DEBUG_INFO = YES; 193 | ONLY_ACTIVE_ARCH = YES; 194 | SDKROOT = iphoneos; 195 | TARGETED_DEVICE_FAMILY = "1,2"; 196 | VERSIONING_SYSTEM = "apple-generic"; 197 | VERSION_INFO_PREFIX = ""; 198 | }; 199 | name = Debug; 200 | }; 201 | BE6B261D1CFA17AF001BFB6F /* Release */ = { 202 | isa = XCBuildConfiguration; 203 | buildSettings = { 204 | ALWAYS_SEARCH_USER_PATHS = NO; 205 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 206 | CLANG_ANALYZER_NONNULL = YES; 207 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 208 | CLANG_CXX_LIBRARY = "libc++"; 209 | CLANG_ENABLE_MODULES = YES; 210 | CLANG_ENABLE_OBJC_ARC = YES; 211 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 212 | CLANG_WARN_BOOL_CONVERSION = YES; 213 | CLANG_WARN_COMMA = YES; 214 | CLANG_WARN_CONSTANT_CONVERSION = YES; 215 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 217 | CLANG_WARN_EMPTY_BODY = YES; 218 | CLANG_WARN_ENUM_CONVERSION = YES; 219 | CLANG_WARN_INFINITE_RECURSION = YES; 220 | CLANG_WARN_INT_CONVERSION = YES; 221 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 222 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 223 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 224 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 225 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 226 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 227 | CLANG_WARN_STRICT_PROTOTYPES = YES; 228 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 229 | CLANG_WARN_UNREACHABLE_CODE = YES; 230 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 231 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 232 | CURRENT_PROJECT_VERSION = 1; 233 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 234 | ENABLE_NS_ASSERTIONS = NO; 235 | ENABLE_STRICT_OBJC_MSGSEND = YES; 236 | GCC_C_LANGUAGE_STANDARD = gnu99; 237 | GCC_NO_COMMON_BLOCKS = YES; 238 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 239 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 240 | GCC_WARN_UNDECLARED_SELECTOR = YES; 241 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 242 | GCC_WARN_UNUSED_FUNCTION = YES; 243 | GCC_WARN_UNUSED_VARIABLE = YES; 244 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 245 | MTL_ENABLE_DEBUG_INFO = NO; 246 | SDKROOT = iphoneos; 247 | SWIFT_COMPILATION_MODE = wholemodule; 248 | TARGETED_DEVICE_FAMILY = "1,2"; 249 | VALIDATE_PRODUCT = YES; 250 | VERSIONING_SYSTEM = "apple-generic"; 251 | VERSION_INFO_PREFIX = ""; 252 | }; 253 | name = Release; 254 | }; 255 | BE6B261F1CFA17AF001BFB6F /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | CLANG_ENABLE_MODULES = YES; 259 | CODE_SIGN_IDENTITY = ""; 260 | DEFINES_MODULE = YES; 261 | DYLIB_COMPATIBILITY_VERSION = 1; 262 | DYLIB_CURRENT_VERSION = 1; 263 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 264 | ENABLE_MODULE_VERIFIER = YES; 265 | INFOPLIST_FILE = Fingertips.xcodeproj/Info.plist; 266 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 267 | LD_RUNPATH_SEARCH_PATHS = ( 268 | "$(inherited)", 269 | "@executable_path/Frameworks", 270 | "@loader_path/Frameworks", 271 | ); 272 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; 273 | PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.Fingertips; 274 | PRODUCT_NAME = "$(TARGET_NAME)"; 275 | SKIP_INSTALL = YES; 276 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 277 | SWIFT_VERSION = 5.0; 278 | }; 279 | name = Debug; 280 | }; 281 | BE6B26201CFA17AF001BFB6F /* Release */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | CLANG_ENABLE_MODULES = YES; 285 | CODE_SIGN_IDENTITY = ""; 286 | DEFINES_MODULE = YES; 287 | DYLIB_COMPATIBILITY_VERSION = 1; 288 | DYLIB_CURRENT_VERSION = 1; 289 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 290 | ENABLE_MODULE_VERIFIER = YES; 291 | INFOPLIST_FILE = Fingertips.xcodeproj/Info.plist; 292 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 293 | LD_RUNPATH_SEARCH_PATHS = ( 294 | "$(inherited)", 295 | "@executable_path/Frameworks", 296 | "@loader_path/Frameworks", 297 | ); 298 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; 299 | PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.Fingertips; 300 | PRODUCT_NAME = "$(TARGET_NAME)"; 301 | SKIP_INSTALL = YES; 302 | SWIFT_VERSION = 5.0; 303 | }; 304 | name = Release; 305 | }; 306 | /* End XCBuildConfiguration section */ 307 | 308 | /* Begin XCConfigurationList section */ 309 | BE6B26101CFA17AF001BFB6F /* Build configuration list for PBXProject "Fingertips" */ = { 310 | isa = XCConfigurationList; 311 | buildConfigurations = ( 312 | BE6B261C1CFA17AF001BFB6F /* Debug */, 313 | BE6B261D1CFA17AF001BFB6F /* Release */, 314 | ); 315 | defaultConfigurationIsVisible = 0; 316 | defaultConfigurationName = Release; 317 | }; 318 | BE6B261E1CFA17AF001BFB6F /* Build configuration list for PBXNativeTarget "Fingertips" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | BE6B261F1CFA17AF001BFB6F /* Debug */, 322 | BE6B26201CFA17AF001BFB6F /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | /* End XCConfigurationList section */ 328 | }; 329 | rootObject = BE6B260D1CFA17AF001BFB6F /* Project object */; 330 | } 331 | --------------------------------------------------------------------------------