diff --git a/.gitignore b/.gitignore index ed3a7ac..11f1ed0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,101 +1,7 @@ - -# Created by https://www.gitignore.io/api/macos,xcode,carthage,cocoapods,fastlane - -### Carthage ### -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -Carthage/Checkouts - -Carthage/Build - -### CocoaPods ### -## CocoaPods GitIgnore Template - -# CocoaPods - Only use to conserve bandwidth / Save time on Pushing -# - Also handy if you have a large number of dependant pods -# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE -Pods/ - -### macOS ### -*.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Xcode ### -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## Build generated -build/ -DerivedData/ - -## Various settings -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 +.DS_Store +/.build +/Packages +/*.xcodeproj xcuserdata/ - -## Other -*.moved-aside -*.xccheckout -*.xcscmblueprint - -### Xcode Patch ### -*.xcodeproj/* -!*.xcodeproj/project.pbxproj -!*.xcodeproj/xcshareddata/ -!*.xcworkspace/contents.xcworkspacedata -/*.gcno - -### fastlane ### -# fastlane - A streamlined workflow tool for Cocoa deployment -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://docs.fastlane.tools/best-practices/source-control/#source-control - -# fastlane specific -/fastlane/README.md -fastlane/report.xml - -# deliver temporary files -fastlane/Preview.html - -# snapshot generated screenshots -fastlane/screenshots/**/*.png -fastlane/screenshots/screenshots.html - -# scan temporary files -fastlane/test_output - -# End of https://www.gitignore.io/api/macos,xcode,carthage,cocoapods,fastlane \ No newline at end of file +DerivedData/ +.swiftpm/ \ No newline at end of file diff --git a/.jazzy.yaml b/.jazzy.yaml deleted file mode 100644 index 2225cd4..0000000 --- a/.jazzy.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# FlyoverKit document generator jazzy settings - -copyright: Copyright 2020 Sven Tiigi -author: Sven Tiigi -github_url: https://github.com/SvenTiigi/FlyoverKit -xcodebuild_arguments: [-target, FlyoverKit-iOS] -clean: true -output: ./Documentation -min_acl: private diff --git a/.swiftlint.yml b/.swiftlint.yml deleted file mode 100644 index f914a3b..0000000 --- a/.swiftlint.yml +++ /dev/null @@ -1,22 +0,0 @@ -opt_in_rules: # some rules are only opt-in - - empty_count - - redundant_nil_coalescing - - switch_case_on_newline - - force_unwrapping - - conditional_returns_on_newline - - closure_spacing - - implicitly_unwrapped_optional - - sorted_imports - -included: - - Sources - -excluded: # paths to ignore during linting. Takes precedence over `included`. - - Tests - - Example - -disabled_rules: # rule identifiers to exclude from running - - trailing_whitespace - - identifier_name - -line_length: 130 \ No newline at end of file diff --git a/Configs/FlyoverKit.plist b/Configs/FlyoverKit.plist deleted file mode 100644 index 4c37321..0000000 --- a/Configs/FlyoverKit.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.3.1 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2018 Sven Tiigi. All rights reserved - NSPrincipalClass - - - diff --git a/Configs/FlyoverKitTests.plist b/Configs/FlyoverKitTests.plist deleted file mode 100644 index 6b123c1..0000000 --- a/Configs/FlyoverKitTests.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.3.1 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/Example/AppDelegate.swift b/Example/AppDelegate.swift deleted file mode 100644 index 0fb12f9..0000000 --- a/Example/AppDelegate.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// AppDelegate.swift -// FlyoverKit-Example -// -// Created by Sven Tiigi on 22.04.18. -// Copyright © 2018 FlyoverKit. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - /// The UINavigationController with ViewController as root - lazy private var navigationController: UINavigationController = { - let navigationController = UINavigationController(rootViewController: ViewController()) - navigationController.navigationBar.prefersLargeTitles = true - navigationController.navigationBar.largeTitleTextAttributes = [ - .foregroundColor: UIColor.main - ] - navigationController.view.backgroundColor = .white - navigationController.navigationBar.tintColor = .main - navigationController.navigationBar.titleTextAttributes = [ - .foregroundColor: UIColor.main - ] - return navigationController - }() - - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - self.window = UIWindow(frame: UIScreen.main.bounds) - self.window?.rootViewController = self.navigationController - self.window?.makeKeyAndVisible() - return true - } - -} diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj new file mode 100644 index 0000000..33cec23 --- /dev/null +++ b/Example/Example.xcodeproj/project.pbxproj @@ -0,0 +1,356 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 3D2A4E212857A0ED00E454D6 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D2A4E202857A0ED00E454D6 /* App.swift */; }; + 3D2A4E232857A0ED00E454D6 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D2A4E222857A0ED00E454D6 /* ContentView.swift */; }; + 3D2A4E252857A0ED00E454D6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D2A4E242857A0ED00E454D6 /* Assets.xcassets */; }; + 3D85E3B0286711B200CDDC8F /* Location.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D85E3AF286711B200CDDC8F /* Location.swift */; }; + 3DCB60562857A10500336B67 /* FlyoverKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3DCB60552857A10500336B67 /* FlyoverKit */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3D2A4E1D2857A0ED00E454D6 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 3D2A4E202857A0ED00E454D6 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; + 3D2A4E222857A0ED00E454D6 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 3D2A4E242857A0ED00E454D6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 3D85E3AF286711B200CDDC8F /* Location.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Location.swift; sourceTree = ""; }; + 3DCB60532857A0FF00336B67 /* FlyoverKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlyoverKit; path = ..; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3D2A4E1A2857A0ED00E454D6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3DCB60562857A10500336B67 /* FlyoverKit in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3D2A4E142857A0ED00E454D6 = { + isa = PBXGroup; + children = ( + 3D2A4E1F2857A0ED00E454D6 /* Example */, + 3D2A4E1E2857A0ED00E454D6 /* Products */, + 3DCB60542857A10500336B67 /* Frameworks */, + 3DCB60532857A0FF00336B67 /* FlyoverKit */, + ); + sourceTree = ""; + }; + 3D2A4E1E2857A0ED00E454D6 /* Products */ = { + isa = PBXGroup; + children = ( + 3D2A4E1D2857A0ED00E454D6 /* Example.app */, + ); + name = Products; + sourceTree = ""; + }; + 3D2A4E1F2857A0ED00E454D6 /* Example */ = { + isa = PBXGroup; + children = ( + 3D2A4E202857A0ED00E454D6 /* App.swift */, + 3D2A4E222857A0ED00E454D6 /* ContentView.swift */, + 3D85E3AF286711B200CDDC8F /* Location.swift */, + 3D2A4E242857A0ED00E454D6 /* Assets.xcassets */, + ); + path = Example; + sourceTree = ""; + }; + 3DCB60542857A10500336B67 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 3D2A4E1C2857A0ED00E454D6 /* Example */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3D2A4E2B2857A0ED00E454D6 /* Build configuration list for PBXNativeTarget "Example" */; + buildPhases = ( + 3D2A4E192857A0ED00E454D6 /* Sources */, + 3D2A4E1A2857A0ED00E454D6 /* Frameworks */, + 3D2A4E1B2857A0ED00E454D6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Example; + packageProductDependencies = ( + 3DCB60552857A10500336B67 /* FlyoverKit */, + ); + productName = Example; + productReference = 3D2A4E1D2857A0ED00E454D6 /* Example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3D2A4E152857A0ED00E454D6 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1340; + LastUpgradeCheck = 1340; + TargetAttributes = { + 3D2A4E1C2857A0ED00E454D6 = { + CreatedOnToolsVersion = 13.4; + }; + }; + }; + buildConfigurationList = 3D2A4E182857A0ED00E454D6 /* Build configuration list for PBXProject "Example" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 3D2A4E142857A0ED00E454D6; + productRefGroup = 3D2A4E1E2857A0ED00E454D6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3D2A4E1C2857A0ED00E454D6 /* Example */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 3D2A4E1B2857A0ED00E454D6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D2A4E252857A0ED00E454D6 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 3D2A4E192857A0ED00E454D6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3D2A4E232857A0ED00E454D6 /* ContentView.swift in Sources */, + 3D85E3B0286711B200CDDC8F /* Location.swift in Sources */, + 3D2A4E212857A0ED00E454D6 /* App.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 3D2A4E292857A0ED00E454D6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.5; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 3D2A4E2A2857A0ED00E454D6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.5; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 3D2A4E2C2857A0ED00E454D6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = de.tiigi.FlyoverKit.Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 3D2A4E2D2857A0ED00E454D6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = ""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = de.tiigi.FlyoverKit.Example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3D2A4E182857A0ED00E454D6 /* Build configuration list for PBXProject "Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3D2A4E292857A0ED00E454D6 /* Debug */, + 3D2A4E2A2857A0ED00E454D6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3D2A4E2B2857A0ED00E454D6 /* Build configuration list for PBXNativeTarget "Example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3D2A4E2C2857A0ED00E454D6 /* Debug */, + 3D2A4E2D2857A0ED00E454D6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCSwiftPackageProductDependency section */ + 3DCB60552857A10500336B67 /* FlyoverKit */ = { + isa = XCSwiftPackageProductDependency; + productName = FlyoverKit; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 3D2A4E152857A0ED00E454D6 /* Project object */; +} diff --git a/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/FlyoverKit.xcodeproj/xcshareddata/xcschemes/FlyoverKit-iOS.xcscheme b/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme similarity index 53% rename from FlyoverKit.xcodeproj/xcshareddata/xcschemes/FlyoverKit-iOS.xcscheme rename to Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme index e6ab2b8..a1a1127 100644 --- a/FlyoverKit.xcodeproj/xcshareddata/xcschemes/FlyoverKit-iOS.xcscheme +++ b/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme @@ -1,6 +1,6 @@ + BlueprintIdentifier = "3D2A4E1C2857A0ED00E454D6" + BuildableName = "Example.app" + BlueprintName = "Example" + ReferencedContainer = "container:Example.xcodeproj"> @@ -26,28 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> - - - - + shouldUseLaunchSchemeArgsEnv = "YES"> - - - - - + + BlueprintIdentifier = "3D2A4E1C2857A0ED00E454D6" + BuildableName = "Example.app" + BlueprintName = "Example" + ReferencedContainer = "container:Example.xcodeproj"> - + - + + BlueprintIdentifier = "3D2A4E1C2857A0ED00E454D6" + BuildableName = "Example.app" + BlueprintName = "Example" + ReferencedContainer = "container:Example.xcodeproj"> - + diff --git a/Example/Example/App.swift b/Example/Example/App.swift new file mode 100644 index 0000000..bdea0de --- /dev/null +++ b/Example/Example/App.swift @@ -0,0 +1,20 @@ +import SwiftUI + +// MARK: - App + +/// The App +@main +struct App {} + +// MARK: - SwiftUI.App + +extension App: SwiftUI.App { + + /// The content and behavior of the app + var body: some Scene { + WindowGroup { + ContentView() + } + } + +} diff --git a/Example/Example/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/Example/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/Example/Example/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Example/Assets.xcassets/Contents.json b/Example/Example/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Example/Example/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Example/ContentView.swift b/Example/Example/ContentView.swift new file mode 100644 index 0000000..0f2430a --- /dev/null +++ b/Example/Example/ContentView.swift @@ -0,0 +1,268 @@ +import FlyoverKit +import MapKit +import SwiftUI + +// MARK: - ContentView + +/// The ContentView +struct ContentView { + + /// Bool value whether Flyover is currently started or stopped + @State + private var isStarted = true + + /// Bool value if options are visible + @State + private var isOptionsVisible = true + + /// The location + @State + private var location: Location = .applePark + + /// The altitude above the ground, measured in meters + @State + private var altitude: Double = 2000 + + /// The viewing angle of the camera, measured in degrees + @State + private var pitch: Double = 50 + + /// The heading step of the camera + @State + private var headingStep: Double = 1.5 + + /// The map type + @State + private var mapType: MKMapType = .standard + +} + +// MARK: - View + +extension ContentView: View { + + /// The content and behavior of the view. + var body: some View { + ZStack { + FlyoverMap( + isStarted: self.isStarted, + coordinate: self.location.coordinate, + configuration: .init( + altitude: .init(self.altitude), + pitch: .init(self.pitch), + heading: .increment(by: self.headingStep) + ), + mapType: self.mapType + ) + .ignoresSafeArea() + self.actionButtons + VStack { + Spacer() + if self.isOptionsVisible { + self.options + .transition( + .opacity.combined(with: .move(edge: .bottom)) + ) + } + } + .padding(.bottom, 35) + self.statusBarOverlay + } + .animation( + .spring(), + value: self.isOptionsVisible + ) + } + +} + +// MARK: - StatusBar Overlay + +private extension ContentView { + + /// A statusbar overlay View + var statusBarOverlay: some View { + GeometryReader { geometry in + Rectangle() + .fill(Color.clear) + .background(.regularMaterial) + .frame(height: geometry.safeAreaInsets.top) + .ignoresSafeArea() + } + } + +} + +// MARK: - Action Buttons + +private extension ContentView { + + /// The action buttons View + var actionButtons: some View { + VStack { + HStack { + Spacer() + VStack { + Button { + self.isStarted.toggle() + } label: { + Image( + systemName: self.isStarted ? "pause.circle" : "play.circle" + ) + .symbolRenderingMode(.hierarchical) + .font(.title) + .foregroundColor(.accentColor) + .padding(5) + .background(.regularMaterial) + .cornerRadius(8) + .shadow(radius: 0.5) + } + Button { + self.isOptionsVisible.toggle() + } label: { + Image( + systemName: self.isOptionsVisible ? "gear.circle.fill" : "gear.circle" + ) + .symbolRenderingMode(.hierarchical) + .font(.title) + .foregroundColor(.accentColor) + .padding(5) + .background(.regularMaterial) + .cornerRadius(8) + .shadow(radius: 0.5) + } + } + } + Spacer() + } + .padding(.trailing, 8) + .padding(.top, 10) + } + +} + +// MARK: - Options + +private extension ContentView { + + /// An options View + var options: some View { + ScrollView( + .horizontal, + showsIndicators: false + ) { + HStack { + self.optionsCell( + title: "Map Type", + content: Picker( + "Map Type", + selection: self.$mapType + ) { + Text( + verbatim: "Standard" + ) + .tag(MKMapType.standard) + Text( + verbatim: "Satellite" + ) + .tag(MKMapType.satellite) + Text( + verbatim: "Hybrid" + ) + .tag(MKMapType.hybrid) + } + .pickerStyle(.menu) + ) + self.optionsCell( + title: "Location", + content: Picker( + "Location", + selection: self.$location + ) { + ForEach( + Location.all, + id: \.self + ) { location in + Text( + verbatim: location.name + ) + .tag(location) + } + } + .pickerStyle(.menu) + ) + self.optionsCell( + title: "Altitude", + content: Slider( + value: self.$altitude, + in: 0...2000, + label: { EmptyView() }, + minimumValueLabel: { Text(verbatim: "") }, + maximumValueLabel: { + Text( + verbatim: "\(Int(self.altitude))m" + ) + .font(.subheadline.monospaced()) + } + ) + .frame(width: 250) + ) + self.optionsCell( + title: "Pitch", + content: Slider( + value: self.$pitch, + in: 0...90, + label: { EmptyView() }, + minimumValueLabel: { Text(verbatim: "") }, + maximumValueLabel: { + Text( + verbatim: "\(Int(self.pitch))" + ) + .font(.subheadline.monospaced()) + } + ) + .frame(width: 200) + ) + self.optionsCell( + title: "Heading Step", + content: Slider( + value: self.$headingStep, + in: 1...10, + label: { EmptyView() }, + minimumValueLabel: { Text(verbatim: "") }, + maximumValueLabel: { + Text( + verbatim: "\(Int(self.headingStep))" + ) + .font(.subheadline.monospaced()) + } + ) + .frame(width: 200) + ) + } + .padding(.horizontal) + } + } + + /// Options cell View + /// - Parameters: + /// - title: The title + /// - content: The Content + func optionsCell( + title: String, + content: Content + ) -> some View { + VStack(alignment: .leading) { + Text( + verbatim: title + ) + .font(.title3.weight(.semibold)) + content + } + .padding() + .background(.regularMaterial) + .cornerRadius(12) + .shadow(radius: 0.5) + } + +} diff --git a/Example/Example/Location.swift b/Example/Example/Location.swift new file mode 100644 index 0000000..0ed7769 --- /dev/null +++ b/Example/Example/Location.swift @@ -0,0 +1,131 @@ +import CoreLocation + +// MARK: - Location + +/// A Location +struct Location { + + /// The name + let name: String + + /// The coordinate + let coordinate: CLLocationCoordinate2D + +} + +// MARK: - Equatable + +extension Location: Equatable { + + /// Returns a Boolean value indicating whether two values are equal + /// - Parameters: + /// - lhs: A value to compare + /// - rhs: Another value to compare + static func == ( + lhs: Self, + rhs: Self + ) -> Bool { + lhs.name == rhs.name + && lhs.coordinate.latitude == rhs.coordinate.latitude + && lhs.coordinate.longitude == rhs.coordinate.longitude + } + +} + +// MARK: - Hashable + +extension Location: Hashable { + + /// Hashes the essential components of this value by feeding them into the given hasher + /// - Parameter hasher: The hasher to use when combining the components of this instance + func hash( + into hasher: inout Hasher + ) { + hasher.combine(self.name) + hasher.combine(self.coordinate.latitude) + hasher.combine(self.coordinate.longitude) + } + +} + +// MARK: - Apple Park + +extension Location { + + /// Apple Park Location + static let applePark = Self( + name: "Apple Park", + coordinate: .init( + latitude: 37.3348, + longitude: -122.0090 + ) + ) + +} + +// MARK: - All + +extension Location { + + /// All locations + static let all: [Self] = [ + .applePark, + .init( + name: "Infinite Loop", + coordinate: .init( + latitude: 37.3317, + longitude: -122.0302 + ) + ), + .init( + name: "Golden Gate Bridge", + coordinate: .init( + latitude: 37.8199, + longitude: -122.4783 + ) + ), + .init( + name: "Coit Tower", + coordinate: .init( + latitude: 37.8024, + longitude: -122.4058 + ) + ), + .init( + name: "Fisherman's Wharf", + coordinate: .init( + latitude: 37.8099, + longitude: -122.4103 + ) + ), + .init( + name: "Ferry Building", + coordinate: .init( + latitude: 37.7956, + longitude: -122.3935 + ) + ), + .init( + name: "Oracle Park", + coordinate: .init( + latitude: 37.7786, + longitude: -122.3893 + ) + ), + .init( + name: "Big Ben", + coordinate: .init( + latitude: 51.4994, + longitude: -0.1245 + ) + ), + .init( + name: "Tower Bridge", + coordinate: .init( + latitude: 51.5055, + longitude: -0.0754 + ) + ) + ] + +} diff --git a/Example/FlyoverConfiguration/FlyoverConfiguration.swift b/Example/FlyoverConfiguration/FlyoverConfiguration.swift deleted file mode 100644 index 6bef65d..0000000 --- a/Example/FlyoverConfiguration/FlyoverConfiguration.swift +++ /dev/null @@ -1,104 +0,0 @@ -// -// Configuration.swift -// FlyoverKit-Example -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import Foundation -import MapKit - -// MARK: - Configuration - -/// The FlyoverConfiguration Enumeration -enum FlyoverConfiguration { - - /// Flyover start/stop boolean - case flyover(Bool) - /// The mapType - case mapType(MKMapType) - /// The duration - case duration(Double) - /// The altitude - case altitude(Double) - /// The pitch - case pitch(Double) - /// The heading step - case headingStep(Double) - - /// Retrieve the Display Name for the Configuration - /// - /// - Returns: The display name string - func getDisplayName() -> String { - switch self { - case .flyover: - return "Flyover" - case .mapType: - return "MapType" - case .duration: - return "Duration" - case .altitude: - return "Altitude" - case .pitch: - return "Pitch" - case .headingStep: - return "HeadingStep" - } - } - - /// Retrieve the minimum Value for Configuration case - /// - /// - Returns: The minimum value - func getMinimumValue() -> Float { - return 0 - } - - /// Retrieve the maximum value for Configuration case - /// - /// - Returns: The maximum value - func getMaximumValue() -> Float { - switch self { - case .duration: - return 50 - case .altitude: - return 2000 - case .pitch: - return 100 - case .headingStep: - return 100 - default: - return 0 - } - } - -} - -// MARK: - RawRepresentable - -extension FlyoverConfiguration: RawRepresentable { - - /// Associated type RawValue as String - typealias RawValue = String - - /// RawRepresentable initializer. Which always returns nil - /// - /// - Parameters: - /// - rawValue: The rawValue - init?(rawValue: String) { - // Returning nil to avoid constructing enum with String - return nil - } - - /// The enumeration name as String - var rawValue: RawValue { - // Retrieve label via Mirror for Enum with associcated value - guard let label = Mirror(reflecting: self).children.first?.label else { - // Return String describing self enumeration with no asscoiated value - return String(describing: self) - } - // Return label - return label - } - -} diff --git a/Example/FlyoverConfiguration/FlyoverConfigurationTableView.swift b/Example/FlyoverConfiguration/FlyoverConfigurationTableView.swift deleted file mode 100644 index 566b5cc..0000000 --- a/Example/FlyoverConfiguration/FlyoverConfigurationTableView.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// FlyoverConfigurationTableView.swift -// FlyoverKit-Example -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import UIKit - -// MARK: - FlyoverConfigurationTableViewDelegate - -/// The FlyoverConfigurationTableViewDelegate -protocol FlyoverConfigurationTableViewDelegate: class { - /// On Configuration Change - /// - /// - Parameter configuration: The updated configuration - func onChange(_ configuration: FlyoverConfiguration) -} - -// MARK: - FlyoverConfigurationTableView - -class FlyoverConfigurationTableView: UITableView { - - // MARK: Properties - - /// The FlyoverConfigurationTableViewDelegate - weak var configurationDelegate: FlyoverConfigurationTableViewDelegate? { - didSet { - // Set delegate on cell - self.cells.forEach { - $0.delegate = self.configurationDelegate - } - } - } - - /// The cells constructed with default configuration and delegate - private lazy var cells: [FlyoverConfigurationTableViewCell] = { - // Initialize default configurations - let defaultConfigurations: [FlyoverConfiguration] = [ - .flyover(true), - .mapType(.standard), - .altitude(600.0), - .pitch(45.0), - .headingStep(20.0), - .duration(4.0) - ] - // Map to Cells - return defaultConfigurations.map { - FlyoverConfigurationTableViewCell($0) - } - }() - - // MARK: Initializer - - /// Default initializer - init() { - // Super init - super.init(frame: .zero, style: .plain) - // Set delegate to self - self.delegate = self - // Set datasource to self - self.dataSource = self - // Clear TableFooterView - self.tableFooterView = UIView() - // Add bottom space - self.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0) - } - - /// Initializer with NSCoder returns nil - required init?(coder aDecoder: NSCoder) { - return nil - } - -} - -// MARK: - UITableViewDataSource - -extension FlyoverConfigurationTableView: UITableViewDataSource { - - func numberOfSections(in tableView: UITableView) -> Int { - // Return 1 section - return 1 - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - // Return count of cells - return self.cells.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - // Return cell at index path - return self.cells[indexPath.row] - } - -} - -// MARK: - UITableViewDelegate - -extension FlyoverConfigurationTableView: UITableViewDelegate { - - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - // First two rows smaller then the rest - return indexPath.row < 2 ? 65 : 100 - } - -} diff --git a/Example/FlyoverConfiguration/FlyoverConfigurationTableViewCell.swift b/Example/FlyoverConfiguration/FlyoverConfigurationTableViewCell.swift deleted file mode 100644 index 782a2c2..0000000 --- a/Example/FlyoverConfiguration/FlyoverConfigurationTableViewCell.swift +++ /dev/null @@ -1,241 +0,0 @@ -// -// FlyoverConfigurationTableViewCell.swift -// FlyoverKit-Example -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import MapKit -import UIKit - -// MARK: - FlyoverConfigurationTableViewCell - -class FlyoverConfigurationTableViewCell: UITableViewCell { - - // MARK: Properties - - /// The Configuration - var configuration: FlyoverConfiguration - - /// The FlyoverConfigurationTableViewDelegate - weak var delegate: FlyoverConfigurationTableViewDelegate? - - /// The title label - lazy var titleLabel: UILabel = { - let label = UILabel() - label.font = .systemFont(ofSize: 18, weight: .semibold) - return label - }() - - /// The value label - lazy var valueLabel: UILabel = { - let label = UILabel() - label.textColor = .lightGray - label.textAlignment = .right - return label - }() - - /// The slider - lazy var slider: UISlider = { - let slider = UISlider() - slider.tintColor = .main - slider.addTarget(self, action: #selector(sliderValueChanged), for: .valueChanged) - slider.addTarget(self, action: #selector(sliderValueDidChanged), for: [.touchUpInside, .touchUpOutside]) - return slider - }() - - /// The switch flyover (start/stop) - lazy var switchFlyover: UISwitch = { - let switchFlyover = UISwitch() - switchFlyover.tintColor = .main - switchFlyover.onTintColor = .main - switchFlyover.addTarget(self, action: #selector(switchValueChanged), for: .valueChanged) - return switchFlyover - }() - - /// The segmented control - lazy var segmentedControl: UISegmentedControl = { - let segmentedControl = UISegmentedControl(items: ["Standard", "SatelliteFlyover", "HybridFlyover"]) - segmentedControl.tintColor = .main - segmentedControl.addTarget(self, action: #selector(segmentedControlValueChanged), for: .valueChanged) - return segmentedControl - }() - - // MARK: Initializer - - /// Default initializer with Configuration - /// - /// - Parameters: - /// - configuration: The Configuration - init(_ configuration: FlyoverConfiguration) { - // Set configuration - self.configuration = configuration - // Super Init - super.init(style: .default, reuseIdentifier: configuration.rawValue) - // Set clear background color - self.backgroundColor = .clear - // Disable selection style - self.selectionStyle = .none - // Switch on configuration to configure and add subviews - switch configuration { - case .flyover(let started): - self.titleLabel.text = self.configuration.getDisplayName() - self.switchFlyover.isOn = started - self.contentView.addSubview(self.titleLabel) - self.contentView.addSubview(self.switchFlyover) - case .mapType: - self.segmentedControl.selectedSegmentIndex = 0 - self.contentView.addSubview(self.segmentedControl) - case .duration(let duration): - self.addSliderConfigurationViews(value: duration) - case .altitude(let altitude): - self.addSliderConfigurationViews(value: altitude) - case .pitch(let pitch): - self.addSliderConfigurationViews(value: pitch) - case .headingStep(let headingStep): - self.addSliderConfigurationViews(value: headingStep) - } - } - - /// Initializer with decoder returns nil - required init?(coder aDecoder: NSCoder) { - return nil - } - - // MARK: View-Lifecycle - - /// LayoutSubviews - override func layoutSubviews() { - super.layoutSubviews() - let height = self.contentView.frame.size.height - let width = self.contentView.frame.size.width - if case .flyover = self.configuration { - self.switchFlyover.frame = CGRect( - x: width - self.switchFlyover.frame.size.width - 15, - y: height/2 - self.switchFlyover.frame.size.height / 2, - width: self.switchFlyover.frame.size.width, - height: self.switchFlyover.frame.size.height - ) - self.titleLabel.frame = CGRect( - x: 15, - y: 0, - width: self.switchFlyover.frame.origin.x, - height: height - ) - } else if case .mapType = self.configuration { - self.segmentedControl.frame = CGRect( - x: 18, - y: (height / 2) - (height - 18 * 2) / 2, - width: width - 18 * 2, - height: height - 18 * 2 - ) - } else { - self.valueLabel.frame = CGRect( - x: width / 2, - y: 0, width: - width / 2 - 15, - height: height / 2 - ) - self.titleLabel.frame = CGRect( - x: 15, - y: 0, - width: self.valueLabel.frame.origin.x, - height: height / 2 - ) - self.slider.frame = CGRect( - x: 15, - y: height / 2, - width: width - 15 * 2, - height: height / 2 - ) - } - } - - /// Add Slider Configuration Views - /// - /// - Parameter value: The slider value - func addSliderConfigurationViews(value: Double) { - self.titleLabel.text = self.configuration.getDisplayName() - self.valueLabel.text = String(describing: value) - self.slider.minimumValue = configuration.getMinimumValue() - self.slider.maximumValue = configuration.getMaximumValue() - self.slider.value = Float(value) - self.contentView.addSubview(self.titleLabel) - self.contentView.addSubview(self.valueLabel) - self.contentView.addSubview(self.slider) - } - - // MARK: Action Handler - - /// Switch value changed action handler - @objc private func switchValueChanged() { - // Check if case is flyover and retrieve associated value bool - if case .flyover(let started) = self.configuration { - // Update configuration with inverted bool value - self.configuration = .flyover(!started) - // OnChange with update configuration - self.delegate?.onChange(self.configuration) - } - } - - /// Slider value changed action handler - @objc private func sliderValueChanged() { - // Set rounded slider value - self.slider.value = roundf(self.slider.value) - // Set value label text - self.valueLabel.text = String(describing: self.slider.value) - } - - /// Slider value did changed action handler - @objc private func sliderValueDidChanged() { - // Set rounded slider value - self.slider.value = roundf(self.slider.value) - // Set value label text - self.valueLabel.text = String(describing: self.slider.value) - // Initialize value of Double slider value type - let value = Double(self.slider.value) - // Declare updated configuration - let updatedConfiguration: FlyoverConfiguration? - // Switch on configuration - switch self.configuration { - case .duration: - updatedConfiguration = .duration(value) - case .altitude: - updatedConfiguration = .altitude(value) - case .pitch: - updatedConfiguration = .pitch(value) - case .headingStep: - updatedConfiguration = .headingStep(value) - default: - updatedConfiguration = nil - } - // Unwrap updatedConfigration - guard let configuration = updatedConfiguration else { - // Not available return - return - } - // Set the configuration - self.configuration = configuration - // OnChange with updated configuration - self.delegate?.onChange(self.configuration) - } - - /// SegmentedControl value changed action handler - @objc private func segmentedControlValueChanged() { - // Switch on selectedSegmentIndex - switch self.segmentedControl.selectedSegmentIndex { - case 0: - self.configuration = .mapType(.standard) - case 1: - self.configuration = .mapType(.satelliteFlyover) - case 2: - self.configuration = .mapType(.hybridFlyover) - default: - self.configuration = .mapType(.standard) - } - // OnChange with updated configuration - self.delegate?.onChange(self.configuration) - } - -} diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 212b38a..0000000 --- a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-Small@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-Small@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-Small-40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-Small-40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-60@3x.png", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-Small.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-Small@2x.png", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-167.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "iTunesArtwork@2x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "pre-rendered" : true - } -} \ No newline at end of file diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-167.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-167.png deleted file mode 100644 index 6a9ebf6..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-167.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png deleted file mode 100644 index 1bcc034..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png deleted file mode 100644 index 171739c..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76.png deleted file mode 100644 index ea3973f..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png deleted file mode 100644 index 7d96313..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png deleted file mode 100644 index c661f93..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png deleted file mode 100644 index 486eb00..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small.png deleted file mode 100644 index dfcc5e5..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png deleted file mode 100644 index b31a3da..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png deleted file mode 100644 index 07b17b3..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png b/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png deleted file mode 100644 index bb759b7..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/Contents.json b/Example/Supporting Files/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/Example/Supporting Files/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Example/Supporting Files/Assets.xcassets/RoundedAppIcon.imageset/Contents.json b/Example/Supporting Files/Assets.xcassets/RoundedAppIcon.imageset/Contents.json deleted file mode 100644 index 0723449..0000000 --- a/Example/Supporting Files/Assets.xcassets/RoundedAppIcon.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "iTunesArtwork@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Example/Supporting Files/Assets.xcassets/RoundedAppIcon.imageset/iTunesArtwork@2x.png b/Example/Supporting Files/Assets.xcassets/RoundedAppIcon.imageset/iTunesArtwork@2x.png deleted file mode 100644 index 43bd619..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/RoundedAppIcon.imageset/iTunesArtwork@2x.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/github.imageset/Contents.json b/Example/Supporting Files/Assets.xcassets/github.imageset/Contents.json deleted file mode 100644 index 1d3ecbb..0000000 --- a/Example/Supporting Files/Assets.xcassets/github.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "icons8-github-filled-26.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "icons8-github-filled-52.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "icons8-github-filled-78.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-26.png b/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-26.png deleted file mode 100644 index 57c743d..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-26.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-52.png b/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-52.png deleted file mode 100644 index 38816c5..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-52.png and /dev/null differ diff --git a/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-78.png b/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-78.png deleted file mode 100644 index 1b6741b..0000000 Binary files a/Example/Supporting Files/Assets.xcassets/github.imageset/icons8-github-filled-78.png and /dev/null differ diff --git a/Example/Supporting Files/Base.lproj/LaunchScreen.storyboard b/Example/Supporting Files/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 14542be..0000000 --- a/Example/Supporting Files/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/Supporting Files/Info.plist b/Example/Supporting Files/Info.plist deleted file mode 100644 index 146985e..0000000 --- a/Example/Supporting Files/Info.plist +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - FlyoverKit - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.3.1 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Example/Supporting Files/SplitScreenViewController.swift b/Example/Supporting Files/SplitScreenViewController.swift deleted file mode 100644 index 46fd374..0000000 --- a/Example/Supporting Files/SplitScreenViewController.swift +++ /dev/null @@ -1,323 +0,0 @@ -// -// SplitScreenViewController.swift -// FlyoverKit-Example -// -// Created by Sven Tiigi on 01.03.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import UIKit - -/// The SplitScreenViewController -open class SplitScreenViewController: UIViewController { - - // MARK: Properties - - /// The TopView - private let topView: UIView - - /// The BottomView - private let bottomView: UIView - - /// The configuration - private let configuration: Configuration - - /// The drag view - private lazy var dragView: UIView = { - return UIView.getUserInteractionEnabledView() - }() - - /// The drag inner view - private lazy var dragInnerView: UIView = { - return UIView.getUserInteractionEnabledView() - }() - - /// The UIPanGestureRecognizer - private lazy var panGestureRecognizer: UIPanGestureRecognizer = { - return UIPanGestureRecognizer(target: self, action: #selector(handleDrag(_:))) - }() - - /// Computed view height - private var viewHeight: CGFloat { - return self.view.frame.size.height - } - - /// Computed view width - private var viewWidth: CGFloat { - return self.view.frame.size.width - } - - // MARK: Initializers - - /// Default initializer with TopView, BottomView and Configuration - /// - /// - Parameters: - /// - topView: The TopView - /// - bottomView: The BottomView - /// - configuration: The SplitScreenViewController.Configuration - public init(topView: UIView, bottomView: UIView, configuration: Configuration = .init()) { - // Set TopView - self.topView = topView - // Set BottomView - self.bottomView = bottomView - // Set Configuration - self.configuration = configuration - // Super init - super.init(nibName: nil, bundle: nil) - // Set Backgroundcolor white - self.view.backgroundColor = .white - // Add drag inner view to drag view - self.dragView.addSubview(self.dragInnerView) - // Add subviews - [self.topView, self.bottomView, self.dragView].forEach(self.view.addSubview) - // Add gesture recognizer on drag view - self.dragView.addGestureRecognizer(self.panGestureRecognizer) - // Set drag view background color - self.dragView.backgroundColor = self.configuration.dragView.backgroundColor - // Set drag inner view background color - self.dragInnerView.backgroundColor = self.configuration.dragInnerView.backgroundColor - // Set drag inner view alpha - self.dragInnerView.alpha = self.configuration.dragInnerView.alpha - // Set drag inner view corner radius - self.dragInnerView.layer.cornerRadius = self.configuration.dragInnerView.cornerRadius - // Clear edges for extended - self.edgesForExtendedLayout = [] - } - - /// Convenience initializer with TopView, BottomView and Configuration Closure - /// - /// - Parameters: - /// - topView: The TopView - /// - bottomView: The BottomView - /// - configuration: The SplitScreenViewController.Configuration Closure - public convenience init(topView: UIView, bottomView: UIView, configuration: (inout Configuration) -> Void) { - // Initialize configuration - var config = Configuration() - // Perform configuration with config - configuration(&config) - // Init with topView, bottomView and config - self.init( - topView: topView, - bottomView: bottomView, - configuration: config - ) - } - - /// Convenience initializer with TopViewController, BottomViewController and Configuration - /// - /// - Parameters: - /// - topViewController: The TopViewController - /// - bottomViewController: The BottomViewController - /// - configuration: The SplitScreenViewController.Configuration - public convenience init(topViewController: UIViewController, bottomViewController: UIViewController, - configuration: Configuration = .init()) { - // Self init with topView, bottomView and configuration - self.init( - topView: topViewController.view, - bottomView: bottomViewController.view, - configuration: configuration - ) - // Add ChildViewControllers - [topViewController, bottomViewController].forEach(self.addChild) - // DidMove to ParentViewController - [topViewController, bottomViewController].forEach { $0.didMove(toParent: self) } - } - - /// Convenience initializer with TopViewController, BottomViewController and Configuration Closure - /// - /// - Parameters: - /// - topViewController: The TopViewController - /// - bottomViewController: The BottomViewController - /// - configuration: The SplitScreenViewController.Configuration Closure - public convenience init(topViewController: UIViewController, bottomViewController: UIViewController, - configuration: (inout Configuration) -> Void) { - // Initialize configuration - var config = Configuration() - // Perform configuration with config - configuration(&config) - // Init with topViewController, bottomViewController and config - self.init( - topViewController: topViewController, - bottomViewController: bottomViewController, - configuration: config - ) - } - - /// NSCoder Initializer (not supported) returns nil - public required init?(coder aDecoder: NSCoder) { - // Return nil - return nil - } - - // MARK: View-Lifecycle - - /// ViewDidLayoutSubView - override open func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - // Check if drag view frame hasn't been set - if self.dragView.frame == CGRect.zero { - // Set drag view Frame - self.dragView.frame.origin.x = 0 - self.dragView.frame.origin.y = self.viewHeight / 2 - self.configuration.dragView.height / 2 - self.dragView.frame.origin.y += self.configuration.dragView.startYPadding - } - // Always Update DragView Width - self.dragView.frame.size.width = self.viewWidth - self.dragView.frame.size.height = self.configuration.dragView.height - // Initialize dragInnerViewHeigh - let dragInnerViewHeight = self.dragView.frame.size.height - self.configuration.dragInnerView.heightPadding * 2 - // Set drag inner view frame - self.dragInnerView.frame = CGRect( - x: self.dragView.frame.size.width / 2 - self.configuration.dragInnerView.width / 2, - y: self.dragView.frame.size.height / 2 - dragInnerViewHeight / 2, - width: self.configuration.dragInnerView.width, - height: dragInnerViewHeight - ) - // Set TopView Frame - self.topView.frame = CGRect( - x: 0, - y: 0, - width: self.viewWidth, - height: self.dragView.frame.origin.y - ) - // Set BottomView Frame - self.bottomView.frame = CGRect( - x: 0, - y: self.dragView.frame.origin.y + self.configuration.dragView.height, - width: self.viewWidth, - height: self.viewHeight - self.dragView.frame.origin.y - ) - } - - // MARK: UIPanGestureRecognizer Handler - - /// Handle UIPanGestureRecognizer drag - /// - /// - Parameter sender: The UIPanGestureRecognizer - @objc private func handleDrag(_ sender: UIPanGestureRecognizer) { - // Initialize gesturerecoggnizer translation for view - let translation = sender.translation(in: self.view) - // Initialize the updated Y origin - let updatedYOrigin = self.dragView.center.y + translation.y - // Check if the new y origin is too small - if updatedYOrigin <= self.configuration.dragThreshold.minY { - // Reached minY threshold - return - } - // Check if the new y origin is too big - if updatedYOrigin >= self.viewHeight - self.configuration.dragThreshold.maxY { - // Reached maxY threshold - return - } - // Update splitViewDrag center - self.dragView.center = CGPoint(x: self.dragView.center.x, y: updatedYOrigin) - // Set view needs layout in order to update the layout - self.view.setNeedsLayout() - // Reset translation - sender.setTranslation(CGPoint.zero, in: self.view) - } - -} - -// MARK: - SplitScreenViewController.Configuration - -public extension SplitScreenViewController { - - /// The SplitScreenViewController Configuration - struct Configuration { - - // MARK: Properties - - // The DragThreshold - public var dragThreshold: DragThreshold - - /// The DragView - public var dragView: DragView - - /// The DragInnerView - public var dragInnerView: DragInnerView - - // MARK: Initializer - - /// Default initializer - public init() { - // Init with default values - self.init( - dragThreshold: ( - minY: 100, - maxY: 100 - ), - dragView: ( - height: 15, - backgroundColor: UIColor(red: 31/255, green: 31/255, blue: 33/255, alpha: 1), - startYPadding: 0 - ), - dragInnerView: ( - width: 80, - heightPadding: 5, - cornerRadius: 5, - backgroundColor: UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 0.8), - alpha: 0.8 - ) - ) - } - - /// Initializer with DragThreshold, DragView and DragInnerView configuration - /// - /// - Parameters: - /// - dragThreshold: The DragThreshold configuration - /// - dragView: The DragView configuration - /// - dragInnerView: The DragInnerView configuration - public init(dragThreshold: DragThreshold, dragView: DragView, dragInnerView: DragInnerView) { - self.dragThreshold = dragThreshold - self.dragView = dragView - self.dragInnerView = dragInnerView - } - - } - -} - -public extension SplitScreenViewController.Configuration { - - /// The DragThreshold configuration type - typealias DragThreshold = ( - minY: CGFloat, - maxY: CGFloat - ) - - /// The DragView configuration type - typealias DragView = ( - height: CGFloat, - backgroundColor: UIColor, - startYPadding: CGFloat - ) - - /// The DragInnerView configuration type - typealias DragInnerView = ( - width: CGFloat, - heightPadding: CGFloat, - cornerRadius: CGFloat, - backgroundColor: UIColor, - alpha: CGFloat - ) - -} - -// MARK: - UIView getUserInteractionEnabledView - -extension UIView { - - /// Retrieve an UIView which user interaction is enabled - /// - /// - Returns: The preconfigured view - static func getUserInteractionEnabledView() -> UIView { - // Initialize the UIView - let view = UIView() - // Set user interaction enabled to true - view.isUserInteractionEnabled = true - // Return view - return view - } - -} diff --git a/Example/Supporting Files/UIColor+Main.swift b/Example/Supporting Files/UIColor+Main.swift deleted file mode 100644 index 50efe6d..0000000 --- a/Example/Supporting Files/UIColor+Main.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// UIColor+Main.swift -// FlyoverKit-Example -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import UIKit - -extension UIColor { - - class var main: UIColor { - return UIColor(red: 1, green: 59 / 255, blue: 48 / 255, alpha: 1) - } - -} diff --git a/Example/ViewController.swift b/Example/ViewController.swift deleted file mode 100644 index 0de5ace..0000000 --- a/Example/ViewController.swift +++ /dev/null @@ -1,158 +0,0 @@ -// -// ViewController.swift -// FlyoverKit-Example -// -// Created by Sven Tiigi on 22.04.18. -// Copyright © 2018 FlyoverKit. All rights reserved. -// - -import FlyoverKit -import MapKit -import SafariServices -import UIKit - -// MARK: - ViewController - -/// The Example View Controller -class ViewController: SplitScreenViewController { - - // MARK: Propertirs - - /// The FlyoverMapView - private var flyoverMapView: FlyoverMapView - - /// The ConfigurationTableView - private var configurationTableView: FlyoverConfigurationTableView - - /// The example location - // Change the enum case to explore different locations 🤙 - let location = FlyoverAwesomePlace.parisEiffelTower - - /// Boolean if MapView is in Full-Screen Mode - var isMapFullscreen = false - - /// Boolean holding Flyover start/stop state - var flyoverWasStarted = true - - // MARK: Initializer - - /// Default initializer - init() { - // Initialize SplitScreenViewController Configuration - var configuration = Configuration() - // Set main backgroundcolor - configuration.dragView.backgroundColor = .main - // Add y padding - configuration.dragView.startYPadding = 20 - // Set white inner drag view background color - configuration.dragInnerView.backgroundColor = .white - // Initialize FlyoverMapView - self.flyoverMapView = FlyoverMapView() - // Initialize ConfigurationTableView - self.configurationTableView = FlyoverConfigurationTableView() - // Super init - super.init(topView: self.flyoverMapView, bottomView: self.configurationTableView, configuration: configuration) - // Set ConfigurationDelegate - self.configurationTableView.configurationDelegate = self - } - - /// Initializer with NSCoder always return nil - required init?(coder aDecoder: NSCoder) { - return nil - } - - // MARK: ViewLifeCycle - - /// ViewDidLoad - override func viewDidLoad() { - super.viewDidLoad() - // Set white background color - self.view.backgroundColor = .white - // Add Navigation Items - self.addNavigationItems() - } - - /// viewDidAppear - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - // Check if flyover was started before starting - if self.flyoverWasStarted { - // Start - self.flyoverMapView.start(flyover: self.location) - } - } - - /// viewDidDisappear - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - // Store state - self.flyoverWasStarted = self.flyoverMapView.state == .started - // Stop - self.flyoverMapView.stop() - } - - // MARK: Custom Functions - - /// Add navigation items - private func addNavigationItems() { - self.title = "FlyoverKit" - let githubBarButtonItem = UIBarButtonItem( - image: #imageLiteral(resourceName: "github"), - style: .plain, - target: self, - action: #selector(githubBarButtonItemTouched(_:)) - ) - self.navigationItem.rightBarButtonItem = githubBarButtonItem - } - - /// Github BarButtonItem touched handler - @objc private func githubBarButtonItemTouched(_ sender: UIBarButtonItem) { - guard let url = URL(string: "https://github.com/SvenTiigi/FlyoverKit/blob/master/README.md") else { - print("Unable to construct Github Repo URL") - return - } - let safariViewController = SFSafariViewController(url: url) - safariViewController.preferredControlTintColor = .main - self.present(safariViewController, animated: true) - } - -} - -// MARK: - ConfigurationTableViewDelegate - -extension ViewController: FlyoverConfigurationTableViewDelegate { - - /// On Configuration Change - /// - /// - Parameter configuration: The updated configuration - func onChange(_ configuration: FlyoverConfiguration) { - // Switch on configuration - switch configuration { - case .flyover(let started): - // Check flyover started/stop state - if started { - // Start - self.flyoverMapView.start(flyover: self.location) - } else { - // Stop - self.flyoverMapView.stop() - } - case .mapType(let mapType): - // Set MapView Type - self.flyoverMapView.mapType = mapType - case .duration(let duration): - // Set duration - self.flyoverMapView.configuration.duration = duration - case .altitude(let altitude): - // Set altitude - self.flyoverMapView.configuration.altitude = altitude - case .pitch(let pitch): - // Set pitch - self.flyoverMapView.configuration.pitch = pitch - case .headingStep(let headingStep): - // Set headingStep - self.flyoverMapView.configuration.headingStep = headingStep - } - } - -} diff --git a/FlyoverKit.podspec b/FlyoverKit.podspec deleted file mode 100644 index 81d37c1..0000000 --- a/FlyoverKit.podspec +++ /dev/null @@ -1,16 +0,0 @@ -Pod::Spec.new do |s| - s.name = "FlyoverKit" - s.version = "1.3.1" - s.summary = "360° flyover on an MKMapView" - s.homepage = "https://github.com/SvenTiigi/FlyoverKit" - s.social_media_url = 'http://twitter.com/SvenTiigi' - s.license = 'MIT' - s.author = { "Sven Tiigi" => "sven.tiigi@gmail.com" } - s.source = { :git => "https://github.com/SvenTiigi/FlyoverKit.git", :tag => s.version.to_s } - s.swift_version = "5.0" - s.ios.deployment_target = "10.0" - s.tvos.deployment_target = "10.0" - s.requires_arc = true - s.source_files = 'Sources/**/*' - s.frameworks = 'UIKit', 'MapKit' -end diff --git a/FlyoverKit.xcodeproj/project.pbxproj b/FlyoverKit.xcodeproj/project.pbxproj deleted file mode 100644 index 6912134..0000000 --- a/FlyoverKit.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1030 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 47; - objects = { - -/* Begin PBXBuildFile section */ - 3D83F777208C7E1900B3FF60 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F776208C7E1900B3FF60 /* AppDelegate.swift */; }; - 3D83F779208C7E1900B3FF60 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F778208C7E1900B3FF60 /* ViewController.swift */; }; - 3D83F77E208C7E1B00B3FF60 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D83F77D208C7E1B00B3FF60 /* Assets.xcassets */; }; - 3D83F781208C7E1B00B3FF60 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3D83F77F208C7E1B00B3FF60 /* LaunchScreen.storyboard */; }; - 3D83F793208C7EA000B3FF60 /* FlyoverCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F787208C7EA000B3FF60 /* FlyoverCamera.swift */; }; - 3D83F795208C7EA000B3FF60 /* FlyoverCamera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F787208C7EA000B3FF60 /* FlyoverCamera.swift */; }; - 3D83F796208C7EA000B3FF60 /* FlyoverCamera+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F788208C7EA000B3FF60 /* FlyoverCamera+State.swift */; }; - 3D83F798208C7EA000B3FF60 /* FlyoverCamera+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F788208C7EA000B3FF60 /* FlyoverCamera+State.swift */; }; - 3D83F799208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F789208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift */; }; - 3D83F79B208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F789208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift */; }; - 3D83F79C208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78A208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift */; }; - 3D83F79E208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78A208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift */; }; - 3D83F79F208C7EA000B3FF60 /* FlyoverAwesomePlace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78C208C7EA000B3FF60 /* FlyoverAwesomePlace.swift */; }; - 3D83F7A1208C7EA000B3FF60 /* FlyoverAwesomePlace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78C208C7EA000B3FF60 /* FlyoverAwesomePlace.swift */; }; - 3D83F7A2208C7EA000B3FF60 /* Flyover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78D208C7EA000B3FF60 /* Flyover.swift */; }; - 3D83F7A4208C7EA000B3FF60 /* Flyover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78D208C7EA000B3FF60 /* Flyover.swift */; }; - 3D83F7A5208C7EA000B3FF60 /* FlyoverMapView+MapType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78F208C7EA000B3FF60 /* FlyoverMapView+MapType.swift */; }; - 3D83F7A7208C7EA000B3FF60 /* FlyoverMapView+MapType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F78F208C7EA000B3FF60 /* FlyoverMapView+MapType.swift */; }; - 3D83F7A8208C7EA000B3FF60 /* FlyoverMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F790208C7EA000B3FF60 /* FlyoverMapViewController.swift */; }; - 3D83F7AA208C7EA000B3FF60 /* FlyoverMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F790208C7EA000B3FF60 /* FlyoverMapViewController.swift */; }; - 3D83F7AB208C7EA000B3FF60 /* FlyoverMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F791208C7EA000B3FF60 /* FlyoverMapView.swift */; }; - 3D83F7AD208C7EA000B3FF60 /* FlyoverMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F791208C7EA000B3FF60 /* FlyoverMapView.swift */; }; - 3D83F7AE208C7EA000B3FF60 /* Flyover+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F792208C7EA000B3FF60 /* Flyover+Operators.swift */; }; - 3D83F7B0208C7EA000B3FF60 /* Flyover+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F792208C7EA000B3FF60 /* Flyover+Operators.swift */; }; - 3D83F7B2208C7F2300B3FF60 /* BaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7B1208C7F2300B3FF60 /* BaseTests.swift */; }; - 3D83F7B4208C7F2300B3FF60 /* BaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7B1208C7F2300B3FF60 /* BaseTests.swift */; }; - 3D83F7B6208C7F4E00B3FF60 /* FlyoverCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7B5208C7F4E00B3FF60 /* FlyoverCameraTests.swift */; }; - 3D83F7B8208C7F4E00B3FF60 /* FlyoverCameraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7B5208C7F4E00B3FF60 /* FlyoverCameraTests.swift */; }; - 3D83F7BA208C7F5900B3FF60 /* FlyoverMapViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7B9208C7F5900B3FF60 /* FlyoverMapViewTests.swift */; }; - 3D83F7BC208C7F5900B3FF60 /* FlyoverMapViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7B9208C7F5900B3FF60 /* FlyoverMapViewTests.swift */; }; - 3D83F7BE208C7F6100B3FF60 /* FlyoverProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7BD208C7F6100B3FF60 /* FlyoverProtocolTests.swift */; }; - 3D83F7C0208C7F6100B3FF60 /* FlyoverProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7BD208C7F6100B3FF60 /* FlyoverProtocolTests.swift */; }; - 3D83F7C4208C82A000B3FF60 /* UIColor+Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7C2208C82A000B3FF60 /* UIColor+Main.swift */; }; - 3D83F7C5208C82A000B3FF60 /* SplitScreenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7C3208C82A000B3FF60 /* SplitScreenViewController.swift */; }; - 3D83F7CA208C831200B3FF60 /* FlyoverConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7C7208C831200B3FF60 /* FlyoverConfiguration.swift */; }; - 3D83F7CB208C831200B3FF60 /* FlyoverConfigurationTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7C8208C831200B3FF60 /* FlyoverConfigurationTableView.swift */; }; - 3D83F7CC208C831200B3FF60 /* FlyoverConfigurationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D83F7C9208C831200B3FF60 /* FlyoverConfigurationTableViewCell.swift */; }; - 3DC2AF4120A39B5B00690DFF /* FlyoverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* FlyoverKit.framework */; }; - 3DC2AF4220A39B5B00690DFF /* FlyoverKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* FlyoverKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 52D6D9871BEFF229002C0205 /* FlyoverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* FlyoverKit.framework */; }; - DD7502921C690C7A006590AF /* FlyoverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D9F01BEFFFBE002C0205 /* FlyoverKit.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 3DC2AF4320A39B5B00690DFF /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 52D6D97B1BEFF229002C0205; - remoteInfo = "FlyoverKit-iOS"; - }; - 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 52D6D97B1BEFF229002C0205; - remoteInfo = FlyoverKit; - }; - DD7502931C690C7A006590AF /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 52D6D9EF1BEFFFBE002C0205; - remoteInfo = "FlyoverKit-tvOS"; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 3DC2AF4520A39B5B00690DFF /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 3DC2AF4220A39B5B00690DFF /* FlyoverKit.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 3D83F774208C7E1900B3FF60 /* FlyoverKit-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "FlyoverKit-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 3D83F776208C7E1900B3FF60 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 3D83F778208C7E1900B3FF60 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 3D83F77D208C7E1B00B3FF60 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 3D83F780208C7E1B00B3FF60 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 3D83F782208C7E1B00B3FF60 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 3D83F787208C7EA000B3FF60 /* FlyoverCamera.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlyoverCamera.swift; sourceTree = ""; }; - 3D83F788208C7EA000B3FF60 /* FlyoverCamera+State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FlyoverCamera+State.swift"; sourceTree = ""; }; - 3D83F789208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FlyoverCamera+Configuration.swift"; sourceTree = ""; }; - 3D83F78A208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FlyoverCamera+RegionChangeAnimation.swift"; sourceTree = ""; }; - 3D83F78C208C7EA000B3FF60 /* FlyoverAwesomePlace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlyoverAwesomePlace.swift; sourceTree = ""; }; - 3D83F78D208C7EA000B3FF60 /* Flyover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Flyover.swift; sourceTree = ""; }; - 3D83F78F208C7EA000B3FF60 /* FlyoverMapView+MapType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FlyoverMapView+MapType.swift"; sourceTree = ""; }; - 3D83F790208C7EA000B3FF60 /* FlyoverMapViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlyoverMapViewController.swift; sourceTree = ""; }; - 3D83F791208C7EA000B3FF60 /* FlyoverMapView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlyoverMapView.swift; sourceTree = ""; }; - 3D83F792208C7EA000B3FF60 /* Flyover+Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Flyover+Operators.swift"; sourceTree = ""; }; - 3D83F7B1208C7F2300B3FF60 /* BaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTests.swift; sourceTree = ""; }; - 3D83F7B5208C7F4E00B3FF60 /* FlyoverCameraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlyoverCameraTests.swift; sourceTree = ""; }; - 3D83F7B9208C7F5900B3FF60 /* FlyoverMapViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlyoverMapViewTests.swift; sourceTree = ""; }; - 3D83F7BD208C7F6100B3FF60 /* FlyoverProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlyoverProtocolTests.swift; sourceTree = ""; }; - 3D83F7C2208C82A000B3FF60 /* UIColor+Main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Main.swift"; sourceTree = ""; }; - 3D83F7C3208C82A000B3FF60 /* SplitScreenViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitScreenViewController.swift; sourceTree = ""; }; - 3D83F7C7208C831200B3FF60 /* FlyoverConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlyoverConfiguration.swift; sourceTree = ""; }; - 3D83F7C8208C831200B3FF60 /* FlyoverConfigurationTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlyoverConfigurationTableView.swift; sourceTree = ""; }; - 3D83F7C9208C831200B3FF60 /* FlyoverConfigurationTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlyoverConfigurationTableViewCell.swift; sourceTree = ""; }; - 52D6D97C1BEFF229002C0205 /* FlyoverKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FlyoverKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 52D6D9861BEFF229002C0205 /* FlyoverKit-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "FlyoverKit-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 52D6D9F01BEFFFBE002C0205 /* FlyoverKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FlyoverKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - AD2FAA261CD0B6D800659CF4 /* FlyoverKit.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = FlyoverKit.plist; sourceTree = ""; }; - AD2FAA281CD0B6E100659CF4 /* FlyoverKitTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = FlyoverKitTests.plist; sourceTree = ""; }; - DD75028D1C690C7A006590AF /* FlyoverKit-tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "FlyoverKit-tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 3D83F771208C7E1900B3FF60 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3DC2AF4120A39B5B00690DFF /* FlyoverKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9781BEFF229002C0205 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9831BEFF229002C0205 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 52D6D9871BEFF229002C0205 /* FlyoverKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9EC1BEFFFBE002C0205 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DD75028A1C690C7A006590AF /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - DD7502921C690C7A006590AF /* FlyoverKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 3D83F775208C7E1900B3FF60 /* Example */ = { - isa = PBXGroup; - children = ( - 3D83F776208C7E1900B3FF60 /* AppDelegate.swift */, - 3D83F778208C7E1900B3FF60 /* ViewController.swift */, - 3D83F7C6208C831200B3FF60 /* FlyoverConfiguration */, - 3D83F7C1208C81D200B3FF60 /* Supporting Files */, - ); - path = Example; - sourceTree = ""; - }; - 3D83F786208C7EA000B3FF60 /* Camera */ = { - isa = PBXGroup; - children = ( - 3D83F787208C7EA000B3FF60 /* FlyoverCamera.swift */, - 3D83F788208C7EA000B3FF60 /* FlyoverCamera+State.swift */, - 3D83F789208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift */, - 3D83F78A208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift */, - ); - path = Camera; - sourceTree = ""; - }; - 3D83F78B208C7EA000B3FF60 /* AwesomePlace */ = { - isa = PBXGroup; - children = ( - 3D83F78C208C7EA000B3FF60 /* FlyoverAwesomePlace.swift */, - ); - path = AwesomePlace; - sourceTree = ""; - }; - 3D83F78E208C7EA000B3FF60 /* MapView */ = { - isa = PBXGroup; - children = ( - 3D83F791208C7EA000B3FF60 /* FlyoverMapView.swift */, - 3D83F78F208C7EA000B3FF60 /* FlyoverMapView+MapType.swift */, - 3D83F790208C7EA000B3FF60 /* FlyoverMapViewController.swift */, - ); - path = MapView; - sourceTree = ""; - }; - 3D83F7C1208C81D200B3FF60 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 3D83F7C3208C82A000B3FF60 /* SplitScreenViewController.swift */, - 3D83F7C2208C82A000B3FF60 /* UIColor+Main.swift */, - 3D83F77D208C7E1B00B3FF60 /* Assets.xcassets */, - 3D83F77F208C7E1B00B3FF60 /* LaunchScreen.storyboard */, - 3D83F782208C7E1B00B3FF60 /* Info.plist */, - ); - path = "Supporting Files"; - sourceTree = ""; - }; - 3D83F7C6208C831200B3FF60 /* FlyoverConfiguration */ = { - isa = PBXGroup; - children = ( - 3D83F7C7208C831200B3FF60 /* FlyoverConfiguration.swift */, - 3D83F7C8208C831200B3FF60 /* FlyoverConfigurationTableView.swift */, - 3D83F7C9208C831200B3FF60 /* FlyoverConfigurationTableViewCell.swift */, - ); - path = FlyoverConfiguration; - sourceTree = ""; - }; - 52D6D9721BEFF229002C0205 = { - isa = PBXGroup; - children = ( - 8933C7811EB5B7E0000D00A4 /* Sources */, - 8933C7831EB5B7EB000D00A4 /* Tests */, - 52D6D99C1BEFF38C002C0205 /* Configs */, - 3D83F775208C7E1900B3FF60 /* Example */, - 52D6D97D1BEFF229002C0205 /* Products */, - ); - sourceTree = ""; - }; - 52D6D97D1BEFF229002C0205 /* Products */ = { - isa = PBXGroup; - children = ( - 52D6D97C1BEFF229002C0205 /* FlyoverKit.framework */, - 52D6D9861BEFF229002C0205 /* FlyoverKit-iOS Tests.xctest */, - 52D6D9F01BEFFFBE002C0205 /* FlyoverKit.framework */, - DD75028D1C690C7A006590AF /* FlyoverKit-tvOS Tests.xctest */, - 3D83F774208C7E1900B3FF60 /* FlyoverKit-Example.app */, - ); - name = Products; - sourceTree = ""; - }; - 52D6D99C1BEFF38C002C0205 /* Configs */ = { - isa = PBXGroup; - children = ( - DD7502721C68FC1B006590AF /* Frameworks */, - DD7502731C68FC20006590AF /* Tests */, - ); - path = Configs; - sourceTree = ""; - }; - 8933C7811EB5B7E0000D00A4 /* Sources */ = { - isa = PBXGroup; - children = ( - 3D83F78D208C7EA000B3FF60 /* Flyover.swift */, - 3D83F792208C7EA000B3FF60 /* Flyover+Operators.swift */, - 3D83F78B208C7EA000B3FF60 /* AwesomePlace */, - 3D83F786208C7EA000B3FF60 /* Camera */, - 3D83F78E208C7EA000B3FF60 /* MapView */, - ); - path = Sources; - sourceTree = ""; - }; - 8933C7831EB5B7EB000D00A4 /* Tests */ = { - isa = PBXGroup; - children = ( - 3D83F7B1208C7F2300B3FF60 /* BaseTests.swift */, - 3D83F7B5208C7F4E00B3FF60 /* FlyoverCameraTests.swift */, - 3D83F7B9208C7F5900B3FF60 /* FlyoverMapViewTests.swift */, - 3D83F7BD208C7F6100B3FF60 /* FlyoverProtocolTests.swift */, - ); - path = Tests; - sourceTree = ""; - }; - DD7502721C68FC1B006590AF /* Frameworks */ = { - isa = PBXGroup; - children = ( - AD2FAA261CD0B6D800659CF4 /* FlyoverKit.plist */, - ); - name = Frameworks; - sourceTree = ""; - }; - DD7502731C68FC20006590AF /* Tests */ = { - isa = PBXGroup; - children = ( - AD2FAA281CD0B6E100659CF4 /* FlyoverKitTests.plist */, - ); - name = Tests; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 52D6D9791BEFF229002C0205 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9ED1BEFFFBE002C0205 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 3D83F773208C7E1900B3FF60 /* FlyoverKit-Example */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3D83F785208C7E1B00B3FF60 /* Build configuration list for PBXNativeTarget "FlyoverKit-Example" */; - buildPhases = ( - 3D83F770208C7E1900B3FF60 /* Sources */, - 3D83F771208C7E1900B3FF60 /* Frameworks */, - 3D83F772208C7E1900B3FF60 /* Resources */, - 3DC2AF4520A39B5B00690DFF /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 3DC2AF4420A39B5B00690DFF /* PBXTargetDependency */, - ); - name = "FlyoverKit-Example"; - productName = Example; - productReference = 3D83F774208C7E1900B3FF60 /* FlyoverKit-Example.app */; - productType = "com.apple.product-type.application"; - }; - 52D6D97B1BEFF229002C0205 /* FlyoverKit-iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "FlyoverKit-iOS" */; - buildPhases = ( - 52D6D9771BEFF229002C0205 /* Sources */, - 52D6D9781BEFF229002C0205 /* Frameworks */, - 52D6D9791BEFF229002C0205 /* Headers */, - 52D6D97A1BEFF229002C0205 /* Resources */, - 3D83F7CD208C874700B3FF60 /* SwiftLint */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "FlyoverKit-iOS"; - productName = FlyoverKit; - productReference = 52D6D97C1BEFF229002C0205 /* FlyoverKit.framework */; - productType = "com.apple.product-type.framework"; - }; - 52D6D9851BEFF229002C0205 /* FlyoverKit-iOS Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "FlyoverKit-iOS Tests" */; - buildPhases = ( - 52D6D9821BEFF229002C0205 /* Sources */, - 52D6D9831BEFF229002C0205 /* Frameworks */, - 52D6D9841BEFF229002C0205 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 52D6D9891BEFF229002C0205 /* PBXTargetDependency */, - ); - name = "FlyoverKit-iOS Tests"; - productName = FlyoverKitTests; - productReference = 52D6D9861BEFF229002C0205 /* FlyoverKit-iOS Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 52D6D9EF1BEFFFBE002C0205 /* FlyoverKit-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "FlyoverKit-tvOS" */; - buildPhases = ( - 52D6D9EB1BEFFFBE002C0205 /* Sources */, - 52D6D9EC1BEFFFBE002C0205 /* Frameworks */, - 52D6D9ED1BEFFFBE002C0205 /* Headers */, - 52D6D9EE1BEFFFBE002C0205 /* Resources */, - 3D83F7CE208C876000B3FF60 /* SwiftLint */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "FlyoverKit-tvOS"; - productName = "FlyoverKit-tvOS"; - productReference = 52D6D9F01BEFFFBE002C0205 /* FlyoverKit.framework */; - productType = "com.apple.product-type.framework"; - }; - DD75028C1C690C7A006590AF /* FlyoverKit-tvOS Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "FlyoverKit-tvOS Tests" */; - buildPhases = ( - DD7502891C690C7A006590AF /* Sources */, - DD75028A1C690C7A006590AF /* Frameworks */, - DD75028B1C690C7A006590AF /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - DD7502941C690C7A006590AF /* PBXTargetDependency */, - ); - name = "FlyoverKit-tvOS Tests"; - productName = "FlyoverKit-tvOS Tests"; - productReference = DD75028D1C690C7A006590AF /* FlyoverKit-tvOS Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 52D6D9731BEFF229002C0205 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 1230; - ORGANIZATIONNAME = FlyoverKit; - TargetAttributes = { - 3D83F773208C7E1900B3FF60 = { - CreatedOnToolsVersion = 9.3; - ProvisioningStyle = Automatic; - }; - 52D6D97B1BEFF229002C0205 = { - CreatedOnToolsVersion = 7.1; - DevelopmentTeam = 9PL44RX378; - LastSwiftMigration = 0930; - }; - 52D6D9851BEFF229002C0205 = { - CreatedOnToolsVersion = 7.1; - LastSwiftMigration = 0930; - }; - 52D6D9EF1BEFFFBE002C0205 = { - CreatedOnToolsVersion = 7.1; - LastSwiftMigration = 0930; - }; - DD75028C1C690C7A006590AF = { - CreatedOnToolsVersion = 7.2.1; - LastSwiftMigration = 0930; - }; - }; - }; - buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "FlyoverKit" */; - compatibilityVersion = "Xcode 6.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 52D6D9721BEFF229002C0205; - productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 3D83F773208C7E1900B3FF60 /* FlyoverKit-Example */, - 52D6D97B1BEFF229002C0205 /* FlyoverKit-iOS */, - 52D6D9EF1BEFFFBE002C0205 /* FlyoverKit-tvOS */, - 52D6D9851BEFF229002C0205 /* FlyoverKit-iOS Tests */, - DD75028C1C690C7A006590AF /* FlyoverKit-tvOS Tests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 3D83F772208C7E1900B3FF60 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D83F781208C7E1B00B3FF60 /* LaunchScreen.storyboard in Resources */, - 3D83F77E208C7E1B00B3FF60 /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D97A1BEFF229002C0205 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9841BEFF229002C0205 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9EE1BEFFFBE002C0205 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DD75028B1C690C7A006590AF /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3D83F7CD208C874700B3FF60 /* SwiftLint */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = SwiftLint; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; - }; - 3D83F7CE208C876000B3FF60 /* SwiftLint */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = SwiftLint; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 3D83F770208C7E1900B3FF60 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D83F7C4208C82A000B3FF60 /* UIColor+Main.swift in Sources */, - 3D83F7C5208C82A000B3FF60 /* SplitScreenViewController.swift in Sources */, - 3D83F7CB208C831200B3FF60 /* FlyoverConfigurationTableView.swift in Sources */, - 3D83F779208C7E1900B3FF60 /* ViewController.swift in Sources */, - 3D83F7CC208C831200B3FF60 /* FlyoverConfigurationTableViewCell.swift in Sources */, - 3D83F7CA208C831200B3FF60 /* FlyoverConfiguration.swift in Sources */, - 3D83F777208C7E1900B3FF60 /* AppDelegate.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9771BEFF229002C0205 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D83F799208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift in Sources */, - 3D83F7AE208C7EA000B3FF60 /* Flyover+Operators.swift in Sources */, - 3D83F7A2208C7EA000B3FF60 /* Flyover.swift in Sources */, - 3D83F7A5208C7EA000B3FF60 /* FlyoverMapView+MapType.swift in Sources */, - 3D83F79F208C7EA000B3FF60 /* FlyoverAwesomePlace.swift in Sources */, - 3D83F79C208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift in Sources */, - 3D83F7A8208C7EA000B3FF60 /* FlyoverMapViewController.swift in Sources */, - 3D83F7AB208C7EA000B3FF60 /* FlyoverMapView.swift in Sources */, - 3D83F796208C7EA000B3FF60 /* FlyoverCamera+State.swift in Sources */, - 3D83F793208C7EA000B3FF60 /* FlyoverCamera.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9821BEFF229002C0205 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D83F7BA208C7F5900B3FF60 /* FlyoverMapViewTests.swift in Sources */, - 3D83F7BE208C7F6100B3FF60 /* FlyoverProtocolTests.swift in Sources */, - 3D83F7B6208C7F4E00B3FF60 /* FlyoverCameraTests.swift in Sources */, - 3D83F7B2208C7F2300B3FF60 /* BaseTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52D6D9EB1BEFFFBE002C0205 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D83F79B208C7EA000B3FF60 /* FlyoverCamera+Configuration.swift in Sources */, - 3D83F7B0208C7EA000B3FF60 /* Flyover+Operators.swift in Sources */, - 3D83F7A4208C7EA000B3FF60 /* Flyover.swift in Sources */, - 3D83F7A7208C7EA000B3FF60 /* FlyoverMapView+MapType.swift in Sources */, - 3D83F7A1208C7EA000B3FF60 /* FlyoverAwesomePlace.swift in Sources */, - 3D83F79E208C7EA000B3FF60 /* FlyoverCamera+RegionChangeAnimation.swift in Sources */, - 3D83F7AA208C7EA000B3FF60 /* FlyoverMapViewController.swift in Sources */, - 3D83F7AD208C7EA000B3FF60 /* FlyoverMapView.swift in Sources */, - 3D83F798208C7EA000B3FF60 /* FlyoverCamera+State.swift in Sources */, - 3D83F795208C7EA000B3FF60 /* FlyoverCamera.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DD7502891C690C7A006590AF /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3D83F7BC208C7F5900B3FF60 /* FlyoverMapViewTests.swift in Sources */, - 3D83F7C0208C7F6100B3FF60 /* FlyoverProtocolTests.swift in Sources */, - 3D83F7B8208C7F4E00B3FF60 /* FlyoverCameraTests.swift in Sources */, - 3D83F7B4208C7F2300B3FF60 /* BaseTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 3DC2AF4420A39B5B00690DFF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 52D6D97B1BEFF229002C0205 /* FlyoverKit-iOS */; - targetProxy = 3DC2AF4320A39B5B00690DFF /* PBXContainerItemProxy */; - }; - 52D6D9891BEFF229002C0205 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 52D6D97B1BEFF229002C0205 /* FlyoverKit-iOS */; - targetProxy = 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */; - }; - DD7502941C690C7A006590AF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 52D6D9EF1BEFFFBE002C0205 /* FlyoverKit-tvOS */; - targetProxy = DD7502931C690C7A006590AF /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 3D83F77F208C7E1B00B3FF60 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 3D83F780208C7E1B00B3FF60 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 3D83F783208C7E1B00B3FF60 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = "$(SRCROOT)/Example/Supporting Files/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "de.tiigi.FlyoverKit-Example"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 3D83F784208C7E1B00B3FF60 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = "$(SRCROOT)/Example/Supporting Files/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "de.tiigi.FlyoverKit-Example"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 52D6D98E1BEFF229002C0205 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 52D6D98F1BEFF229002C0205 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 52D6D9911BEFF229002C0205 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 9PL44RX378; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = Configs/FlyoverKit.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - ONLY_ACTIVE_ARCH = NO; - PRODUCT_BUNDLE_IDENTIFIER = "de.tiigi.FlyoverKit-iOS"; - PRODUCT_NAME = FlyoverKit; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 52D6D9921BEFF229002C0205 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 9PL44RX378; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = Configs/FlyoverKit.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "de.tiigi.FlyoverKit-iOS"; - PRODUCT_NAME = FlyoverKit; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 52D6D9941BEFF229002C0205 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - INFOPLIST_FILE = Configs/FlyoverKitTests.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.FlyoverKit.FlyoverKit-iOS-Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 52D6D9951BEFF229002C0205 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - INFOPLIST_FILE = Configs/FlyoverKitTests.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.FlyoverKit.FlyoverKit-iOS-Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 52D6DA021BEFFFBE002C0205 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = Configs/FlyoverKit.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "de.tiigi.FlyoverKit-tvOS"; - PRODUCT_NAME = FlyoverKit; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 10.0; - }; - name = Debug; - }; - 52D6DA031BEFFFBE002C0205 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = Configs/FlyoverKit.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "de.tiigi.FlyoverKit-tvOS"; - PRODUCT_NAME = FlyoverKit; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 10.0; - }; - name = Release; - }; - DD7502961C690C7A006590AF /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - INFOPLIST_FILE = Configs/FlyoverKitTests.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.FlyoverKit.FlyoverKit-tvOS-Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TVOS_DEPLOYMENT_TARGET = 10.0; - }; - name = Debug; - }; - DD7502971C690C7A006590AF /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - INFOPLIST_FILE = Configs/FlyoverKitTests.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.FlyoverKit.FlyoverKit-tvOS-Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TVOS_DEPLOYMENT_TARGET = 10.0; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 3D83F785208C7E1B00B3FF60 /* Build configuration list for PBXNativeTarget "FlyoverKit-Example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3D83F783208C7E1B00B3FF60 /* Debug */, - 3D83F784208C7E1B00B3FF60 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "FlyoverKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 52D6D98E1BEFF229002C0205 /* Debug */, - 52D6D98F1BEFF229002C0205 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "FlyoverKit-iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 52D6D9911BEFF229002C0205 /* Debug */, - 52D6D9921BEFF229002C0205 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "FlyoverKit-iOS Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 52D6D9941BEFF229002C0205 /* Debug */, - 52D6D9951BEFF229002C0205 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "FlyoverKit-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 52D6DA021BEFFFBE002C0205 /* Debug */, - 52D6DA031BEFFFBE002C0205 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "FlyoverKit-tvOS Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DD7502961C690C7A006590AF /* Debug */, - DD7502971C690C7A006590AF /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 52D6D9731BEFF229002C0205 /* Project object */; -} diff --git a/FlyoverKit.xcodeproj/xcshareddata/xcschemes/FlyoverKit-tvOS.xcscheme b/FlyoverKit.xcodeproj/xcshareddata/xcschemes/FlyoverKit-tvOS.xcscheme deleted file mode 100644 index 23f7687..0000000 --- a/FlyoverKit.xcodeproj/xcshareddata/xcschemes/FlyoverKit-tvOS.xcscheme +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/LICENSE b/LICENSE index 7692b3f..9a589c9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2020 Sven Tiigi +The MIT License (MIT) + +Copyright (c) 2022 Sven Tiigi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -7,13 +9,14 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Package.swift b/Package.swift index 1bb3773..7a7c64d 100644 --- a/Package.swift +++ b/Package.swift @@ -1,30 +1,25 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.2 import PackageDescription let package = Package( name: "FlyoverKit", platforms: [ - .iOS(.v10), - .tvOS(.v10) + .iOS(.v13), + .tvOS(.v13) ], products: [ .library( name: "FlyoverKit", - targets: ["FlyoverKit"] - ), + targets: [ + "FlyoverKit" + ] + ) ], - dependencies: [], targets: [ .target( name: "FlyoverKit", - dependencies: [], path: "Sources" - ), - .testTarget( - name: "FlyoverKitTests", - dependencies: ["FlyoverKit"], - path: "Tests" - ), + ) ] ) diff --git a/README.md b/README.md index 31f70d9..5c6b2a3 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,56 @@ +
+

- FlyoverKit Header Logo + logo

+

+ FlyoverKit +

+

- - Swift 5.0 - - + A Swift Package to easily perform flyovers on a MKMapView. +

+ +

+ CI Status - - Version - - - Carthage Compatible - - - Platform - - - Documentation - - - Twitter - + + Documentation + + Platform + + Twitter +

-
- -`FlyoverKit` enables you to present stunning 360° flyover views on an `MKMapView` with zero effort while maintaining full configuration possibilities. `FlyoverKit` builds the core of [STLocationRequest](https://github.com/SvenTiigi/STLocationRequest) which enables you a way to request the user location services via a 3D 360° flyover MapView. - -## Example - -Example Application Screenshot - -The example Application is an excellent way to see `FlyoverKit` in action. You get a brief look of the available configuration options and how they affect the flyover behaviour. Simply open the `FlyoverKit.xcodeproj` and run the `FlyoverKit-Example` scheme. Please keep in mind that the `SatelliteFlyover` and `HybridFlyover` will only work on a real iOS device. - -## Installation - -### CocoaPods - -FlyoverKit is available through [CocoaPods](http://cocoapods.org). To install -it, simply add the following line to your Podfile: +```swift +import SwiftUI +import FlyoverKit -```bash -pod 'FlyoverKit' +struct ContentView: View { + + var body: some View { + FlyoverMap( + coordinate: .init( + latitude: 37.8023, + longitude: -122.4057 + ) + ) + } + +} ``` -### Carthage - -[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. - -To integrate FlyoverKit into your Xcode project using Carthage, specify it in your `Cartfile`: +## Features -```ogdl -github "SvenTiigi/FlyoverKit" -``` - -Run `carthage update --platform iOS` to build the framework and drag the built `FlyoverKit.framework` into your Xcode project. +- [x] Configurable flyovers on a MKMapView 🚁 +- [x] Easily start, stop and resume flyovers ⚙️ +- [x] Support for SwiftUI and UIKit 🧑‍🎨 +- [x] Runs on iOS and tvOS 📱 📺 -On your application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase” and add the Framework path as mentioned in [Carthage Getting started Step 4, 5 and 6](https://github.com/Carthage/Carthage/blob/master/README.md) +## Installation ### Swift Package Manager @@ -67,247 +58,84 @@ To integrate using Apple's [Swift Package Manager](https://swift.org/package-man ```swift dependencies: [ - .package(url: "https://github.com/SvenTiigi/FlyoverKit.git", from: "1.3.1") + .package(url: "https://github.com/SvenTiigi/FlyoverKit.git", from: "2.0.0") ] ``` -### Manually +Or navigate to your Xcode project then select `Swift Packages`, click the “+” icon and search for `FlyoverKit`. -If you prefer not to use any of the aforementioned dependency managers, you can integrate FlyoverKit into your project manually. Simply drag the `Sources` Folder into your Xcode project. - -## Usage -`FlyoverKit` can be implemented in three different ways. Simply choose the most suitable type for your implementation. Please see the [Advanced](https://github.com/SvenTiigi/FlyoverKit#advanced) section in order to configure the `FlyoverKit` to your needs. - -### FlyoverCamera -If you already have a `MKMapView` in your `Controller` and you want to add a flyover to this MapView, simply use the `FlyoverCamera`. - -```swift -import FlyoverKit - -// Initialize the FlyoverCamera with an already existing MKMapView -let flyoverCamera = FlyoverCamera(mapView: self.mapView) - -// Initialize a location via CLLocationCoordinate2D -let eiffelTower = CLLocationCoordinate2D(latitude: 48.858370, longitude: 2.294481) - -// Start flyover -flyoverCamera.start(flyover: eiffelTower) -``` - -### FlyoverMapView -If you wish to show a MapView which is already preconfigured to perform a flyover on a given location, you should use the `FlyoverMapView`. - -```swift -import FlyoverKit +## Example -// Initialize the FlyoverMapView -let flyoverMapView = FlyoverMapView() +Check out the example application to see FlyoverKit in action. Simply open the `Example/Example.xcodeproj` and run the "Example" scheme. -// Initialize a location via CLLocation -let eiffelTower = CLLocation(latitude: 48.858370, longitude: 2.294481) +## Usage -// Start flyover -flyoverMapView.start(flyover: eiffelTower) -``` +### SwiftUI -### FlyoverMapViewController -If you wish to present a `UIViewController` with an embedded `FlyoverMapView` to perform a flyover on a given location, `FlyoverMapViewController` is at your service. +When using SwiftUI a `FlyoverMap` can be used to render and control a flyover. ```swift -import FlyoverKit - -// Initialize a location via FlyoverAwesomePlace -let eiffelTower = FlyoverAwesomePlace.parisEiffelTower - -// Initialize the FlyoverMapViewController with a Flyover object -let controller = FlyoverMapViewController(flyover: eiffelTower) - -// Present controller -self.present(controller, animated: true) +FlyoverMap( + // Bool value if flyover is started or stopped + isStarted: true, + // The coordinate to perform the flyover on + coordinate: CLLocationCoordinate2D( + latitude: 37.8023, + longitude: -122.4057 + ), + configuration: Flyover.Configuration( + // The animation curve + animationCurve: .linear, + // The altitude in meter + altitude: 900, + // The pitch in degree + pitch: 45.0, + // The heading step + headingStep: .incremented(by: 1.5) + ), + // The map type e.g. .standard, .satellite, .hybrid + mapType: .standard +) ``` -## Advanced -The `FlyoverKit` consists of three main components. The `Flyover` protocol, `FlyoverCamera` and `FlyoverMapView`.  - -
-

- Architecture -
-

- -## Flyover Protocol -The `flyover` protocol specifies a type with a `CLLocationCoordinat2D` property. It is used to perform a flyover on the given coordinate. +### UIKit ```swift -public protocol Flyover { - var coordinate: CLLocationCoordinate2D { get } -} -``` -The `FlyoverKit` already implemented this protocol to various MapKit and CoreLocation types like `CLLocationCoordinate2D`, `CLLocation`, `MKMapPoint`, `MKMapItem`, `MKCoordinateRegion` and many [more](https://sventiigi.github.io/FlyoverKit/Extensions.html). - -You can apply the `Flyover` protocol to your own models to use them for a flyover. +let flyoverMapView = FlyoverMapView() -```swift -struct Address { - var name: String - var coordinate: CLLocationCoordinate2D +if flyoverMapView.isFlyoverStarted { + // ... } -extension Address: Flyover {} -``` - -### Operators -In order to compare two `Flyover` types you can use the following two operators. - -#### Equatable operator (==) - -```swift -self.flyover1 == self.flyover2 -``` -> Checks if the two given Flyover types are exactly the same via comparison of latitude and longitude. - -#### Rounded Equatable operator (~~) - -```swift -self.flyover1 ~~ self.flyover2 -``` -> Checks if the two given Flyover types are nearly the same via comparison of rounded latitude and longitude. - -### FlyoverAwesomePlace -The `FlyoverAwesomePlace` is a `Flyover` protocol compliant Enumeration with awesome locations and landmarks like `NewYorkStatueOfLiberty`, `GooglePlex`, `SydneyOperaHouse` and many [more](https://sventiigi.github.io/FlyoverKit/Enums/FlyoverAwesomePlace.html). You can use them in your own implementation or to explore different locations in the `FlyoverKitExample` Application. - -## FlyoverCamera -The `FlyoverCamera` is responsible for manipulating the `MKMapView` camera and performs a 360° flyover animation via [UIViewPropertyAnimator](https://developer.apple.com/documentation/uikit/uiviewpropertyanimator). - -In order to initialize a `FlyoverCamera` object you need to pass a `MKMapView` (which reference will be weakly stored) and a `FlyoverCamera.Configuration` object. - -```swift -// Initialize FlyoverCamera configuration -let configuration = FlyoverCamera.Configuration( - duration: 4.0, - altitude: 600.0, - pitch: 45.0, - headingStep: 20.0 -) - -// Initialize FlyoverCamera -let camera = FlyoverCamera( - mapView: mapView, - configuration: configuration -) - -// Start Flyover -camera.start(flyover: location) -``` -### Configuration -The `FlyoverCamera.Configuration` struct holds all specific flyover configuration values. Set the properties to get the right look and feel of the flyover as you need it to be. - -| Configuration | Description | -| ------------- | ------------- | -| duration | The flyover animation duration | -| altitude | The altitude above the ground, measured in meters | -| pitch | The viewing angle of the camera, measured in degrees | -| headingStep | The direction step in degrees that is added to the MapViewCamera heading in each flyover iteration | -| regionChangeAnimation | The region change animation that should be applied if a flyover has been started and the MapCamera has to change the region. Default is always `.none` which immediately present the place. If you wish that the region change should be performed via an animation you can set `.animated(duration: 1.5, curve: .easeIn)` | - -An excellent visualization of an `MKMapCamera` from [TechTopia](http://www.techotopia.com/index.php/An_iOS_9_MapKit_Flyover_Tutorial) - -

- - Flyover Camera Diagram - -

- -### Configuration Theme -If you don't want to set the properties yourself you can use a preconfigured configuration theme. Currently there are four themes available - -| Theme | Description | -| ------------- | ------------- | -| default | Default flyover configuration with configuration for a default flyover usage | -| lowFlying | Flyover configuration with a low altitude and a high pitch. Simulates a low flying helicopter viewing angle | -| farAway | Configuration with a high altitude and a normal pitch which results in a far away viewing angle | -| giddy | A giddy configuration 🤢 which you shouldn't use in production. But it's fun 🤷‍♂️ 🤙| -| astronautView | The view of an astronaut 🌎 | - -Furthermore, you can initialize a `FlyoverCamera` with a given `Theme`. - -```swift -// Initialize FlyoverCamera -let camera = FlyoverCamera( - mapView: mapView, +flyoverMapView.startFlyover( + at: CLLocationCoordinate2D( + latitude: 37.8023, + longitude: -122.4057 + ), configuration: .default ) -``` - -More themes coming soon... 👨‍💻 - -## FlyoverMapView -The `FlyoverMapView` is a preconfigured `MKMapView` with an embedded `FlyoverCamera`. The `FlyoverMapView` offers various convenience functions for example starting a flyover with a `MKAnnotation` object or setting a supported flyover `MapType`. -```swift -// Initialize with default configuration theme and standard MapType -let flyoverMapView = FlyoverMapView() +flyoverMapView.stopFlyover() -// Or initialize by setting a different theme and the satelliteFlyover MapType -let flyoverMapView = FlyoverMapView(configuration: .farAway, mapType: .satelliteFlyover) +flyoverMapView.resumeFlyover() ``` -### MapType -The `FlyoverMapView.MapType` specifies the three supported `MKMapType`'s. +### Flyover -| MapType | Description | -| ------------- | ------------- | -| standard | A street map that shows the position of all roads and shows 3D buildings | -| satelliteFlyover | A satellite image of the area with road and road name information layered on top | -| hybridFlyover | A hybrid satellite image with flyover data where available | - -### FlyoverMapViewController -The `FlyoverMapViewController` is an easy and simple way to present a `UIViewController` with an embedded `FlyoverMapView`. You can use it if you just want to present a 360° flyover on a given `Flyover` type. +A `Flyover` object represents the core object to start, stop and resume a flyover on an instance of `MKMapView`. ```swift -// Initialize a location -let eiffelTower = CLLocationCoordinate2DMake(48.858370, 2.294481) - -// Initialize the FlyoverMapViewController with a Flyover object -let controller = FlyoverMapViewController(flyover: eiffelTower) - -// Present controller -self.present(controller, animated: true) -``` - -Additionally you can initialize the `FlyoverMapViewController` with your own `Configuration` or `Configuration.Theme` and a `MapType` - -```swift -// Initialize a location -let eiffelTower = CLLocationCoordinate2DMake(48.858370, 2.294481) - -// Initialize a Configuration -let configuration = FlyoverCamera.Configuration( - duration: 4.0, - altitude: 600.0, - pitch: 45.0, - headingStep: 20.0 -) - -// Initialize the FlyoverMapViewController -let controller = FlyoverMapViewController( - flyover: eiffelTower, - configuration: configuration, - mapType: .satelliteFlyover +let flyover = Flyover( + mapView: self.mapView ) - -// Present controller -self.present(controller, animated: true) ``` - -## Contributing -Contributions are very welcome 🙌 🤓 +> Note: The provided MKMapView is always weakly referenced ## License ``` FlyoverKit -Copyright (c) 2020 Sven Tiigi +Copyright (c) 2022 Sven Tiigi sven.tiigi@gmail.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Sources/AwesomePlace/FlyoverAwesomePlace.swift b/Sources/AwesomePlace/FlyoverAwesomePlace.swift deleted file mode 100644 index bd7ec96..0000000 --- a/Sources/AwesomePlace/FlyoverAwesomePlace.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// FlyoverAwesomePlace.swift -// FlyoverKit -// -// Created by Sven Tiigi on 22.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import CoreLocation - -// MARK: - FlyoverAwesomePlace - -/// Awesome 360° locations and landmarks like -/// NewYorkStatueOfLiberty, GooglePlex, SydneyOperaHouse and many more. -public enum FlyoverAwesomePlace: String, Codable, Equatable, Hashable, CaseIterable { - // MARK: USA - /// New York Statue of Liberty - case newYorkStatueOfLiberty - /// New York Manhatten - case newYork - /// San Francisco Golden Gate Bridge - case sanFranciscoGoldenGateBridge - /// New York Central Park - case centralParkNY - /// Google Plex - case googlePlex - /// Miami Beach - case miamiBeach - /// Laguna Beach - case lagunaBeach - /// Griffith Observatory - case griffithObservatory - /// Luxor Resort Las Vegas - case luxorResortLasVegas - /// Apple Headquarter - case appleHeadquarter - // MARK: Germany - /// Berlin Brandenbuger Gate - case berlinBrandenburgerGate - /// Hamburg Townhall - case hamburgTownHall - /// Cologne Cathedral - case cologneCathedral - /// Munic Church - case munichCurch - /// Neuschwanstein Castle - case neuschwansteinCastle - /// Hamburg Elb-Philharmonic - case hamburgElbPhilharmonic - /// Muenster Castle - case muensterCastle - // MARK: Italy - /// Colosseum Rom - case romeColosseum - /// Piazza Di Trevi - case piazzaDiTrevi - // MARK: Spain - /// Sagrade Familia Spain - case sagradaFamiliaSpain - // MARK: England - /// London Big Ben - case londonBigBen - /// London Eye - case londonEye - // MARK: Australia - /// Opera House Sydney - case sydneyOperaHouse - // MARK: France - /// Paris Eiffel Tower - case parisEiffelTower -} - -// MARK: - FlyoverAwesomePlace Flyover Extension - -extension FlyoverAwesomePlace: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - switch self { - case .newYorkStatueOfLiberty: - return .init(latitude: 40.689249, longitude: -74.044500) - case .newYork: - return .init(latitude: 40.702749, longitude: -74.014120) - case .sanFranciscoGoldenGateBridge: - return .init(latitude: 37.826040, longitude: -122.479448) - case .centralParkNY: - return .init(latitude: 40.779269, longitude: -73.963201) - case .googlePlex: - return .init(latitude: 37.422001, longitude: -122.084109) - case .miamiBeach: - return .init(latitude: 25.791007, longitude: -80.148082) - case .lagunaBeach: - return .init(latitude: 33.543361, longitude: -117.792315) - case .griffithObservatory: - return .init(latitude: 34.118536, longitude: -118.300446) - case .luxorResortLasVegas: - return .init(latitude: 36.095511, longitude: -115.176072) - case .appleHeadquarter: - return .init(latitude: 37.332100, longitude: -122.029642) - case .berlinBrandenburgerGate: - return .init(latitude: 52.516275, longitude: 13.377704) - case .hamburgTownHall: - return .init(latitude: 53.550416, longitude: 9.992527) - case .cologneCathedral: - return .init(latitude: 50.941278, longitude: 6.958281) - case .munichCurch: - return .init(latitude: 48.138631, longitude: 11.573625) - case .neuschwansteinCastle: - return .init(latitude: 47.557574, longitude: 10.749800) - case .hamburgElbPhilharmonic: - return .init(latitude: 53.541227, longitude: 9.984075) - case .muensterCastle: - return .init(latitude: 51.963691, longitude: 7.611546) - case .romeColosseum: - return .init(latitude: 41.89021, longitude: 12.492231) - case .piazzaDiTrevi: - return .init(latitude: 41.900865, longitude: 12.483345) - case .sagradaFamiliaSpain: - return .init(latitude: 41.404024, longitude: 2.174370) - case .londonBigBen: - return .init(latitude: 51.500729, longitude: -0.124625) - case .londonEye: - return .init(latitude: 51.503324, longitude: -0.119543) - case .sydneyOperaHouse: - return .init(latitude: -33.857197, longitude: 151.215140) - case .parisEiffelTower: - return .init(latitude: 48.85815, longitude: 2.29452) - } - } - -} diff --git a/Sources/Camera/FlyoverCamera+Configuration.swift b/Sources/Camera/FlyoverCamera+Configuration.swift deleted file mode 100644 index ef53a18..0000000 --- a/Sources/Camera/FlyoverCamera+Configuration.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// FlyoverCamera+Configuration.swift -// FlyoverKit -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import CoreLocation - -// MARK: - Configuration - -public extension FlyoverCamera { - - /// The FlyoverCamera Configuration - struct Configuration: Equatable, Hashable { - - /// The duration - public var duration: TimeInterval - - /// The altitude above the ground, measured in meters - public var altitude: CLLocationDistance - - /// The viewing angle of the camera, measured in degrees - public var pitch: Double - - /// The heading step - public var headingStep: CLLocationDirection - - /// The region change animation - public var regionChangeAnimation: RegionChangeAnimation - - /// Default initializer - /// - /// - Parameters: - /// - duration: The duration - /// - altitude: The altitude - /// - pitch: The pitch - /// - headingStep: The heading step - /// - regionChangeAnimation: The region change animation. Default value `none` - public init(duration: TimeInterval, - altitude: CLLocationDistance, - pitch: Double, - headingStep: Double, - regionChangeAnimation: RegionChangeAnimation = .none) { - self.duration = duration - self.altitude = altitude - self.pitch = pitch - self.headingStep = headingStep - self.regionChangeAnimation = regionChangeAnimation - } - } - -} - -// MARK: - Configuration Theme - -public extension FlyoverCamera.Configuration { - - /// Default configuration - static let `default` = FlyoverCamera.Configuration( - duration: 4.0, - altitude: 600, - pitch: 45.0, - headingStep: 20.0 - ) - - /// Low flying configuration - static let lowFlying = FlyoverCamera.Configuration( - duration: 4.0, - altitude: 65, - pitch: 80, - headingStep: 20 - ) - - /// Far away configuration - static let farAway = FlyoverCamera.Configuration( - duration: 4.0, - altitude: 1330, - pitch: 55, - headingStep: 20 - ) - - //// Giddy configuration - static let giddy = FlyoverCamera.Configuration( - duration: 0.0, - altitude: 250, - pitch: 80, - headingStep: 50 - ) - - /// Astronaut view configuration - static let astronautView = FlyoverCamera.Configuration( - duration: 20.0, - altitude: 2000.0, - pitch: 100.0, - headingStep: 35.0 - ) - -} diff --git a/Sources/Camera/FlyoverCamera+RegionChangeAnimation.swift b/Sources/Camera/FlyoverCamera+RegionChangeAnimation.swift deleted file mode 100644 index 0fb25f3..0000000 --- a/Sources/Camera/FlyoverCamera+RegionChangeAnimation.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// FlyoverCamera+RegionChangeAnimation.swift -// FlyoverKit -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import UIKit - -public extension FlyoverCamera { - - /// The RegionChangeAnimation Enum specifies if the - /// switch/transition to a new coordinate should be animated or not - enum RegionChangeAnimation: Equatable, Hashable { - /// No animation should be applied - case none - /// Animation with given TimeInterval and AnimationCurve - /// should be performed - case animated(duration: TimeInterval, curve: UIView.AnimationCurve) - } - -} diff --git a/Sources/Camera/FlyoverCamera+State.swift b/Sources/Camera/FlyoverCamera+State.swift deleted file mode 100644 index 275d1b5..0000000 --- a/Sources/Camera/FlyoverCamera+State.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// FlyoverCamera+State.swift -// FlyoverKit -// -// Created by Sven Tiigi on 28.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import Foundation - -public extension FlyoverCamera { - - /// The FlyoverCamera State - /// - /// - started: The FlyoverCamera is started and running - /// - stopped: The FlyoverCamera is stopped (Initial-Value) - enum State: String, Equatable, Hashable, CaseIterable { - /// Started - case started - /// Stopped - case stopped - } - -} diff --git a/Sources/Camera/FlyoverCamera.swift b/Sources/Camera/FlyoverCamera.swift deleted file mode 100644 index efcbe79..0000000 --- a/Sources/Camera/FlyoverCamera.swift +++ /dev/null @@ -1,274 +0,0 @@ -// -// FlyoverCamera.swift -// FlyoverKit -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import MapKit - -// MARK: - FlyoverCamera - -/// The FlyoverCamera -open class FlyoverCamera { - - // MARK: Public properties - - /// The configuration - open var configuration: Configuration { - willSet { - // Force stop animation - self.animator?.forceStopAnimation() - } - didSet { - // Set MapCamera altitude - self.mapCamera.altitude = self.configuration.altitude - // Set MapCamera pitch - self.mapCamera.pitch = CGFloat(self.configuration.pitch) - // Restart flyover with current flyover - self.performFlyover(self.flyover) - } - } - - /// Retrieve FlyoverCamera State - open var state: State - - /// The animation curve - open var curve: UIView.AnimationCurve = .linear - - // MARK: Private properties - - /// The MapView - private weak var mapView: MKMapView? - - /// The MapView Camera - private lazy var mapCamera: MKMapCamera = { - let camera = MKMapCamera() - camera.altitude = self.configuration.altitude - camera.pitch = CGFloat(self.configuration.pitch) - return camera - }() - - /// The flyover - private var flyover: Flyover? - - /// The UIViewPropertyAnimator - private var animator: UIViewPropertyAnimator? - - // MARK: Initializer - - /// Default Initializer - /// - /// - Parameters: - /// - mapView: The MapView - /// - configuration: The Configuration. Default value: `.default` theme - public init(mapView: MKMapView, configuration: Configuration = .default) { - // Set MapView - self.mapView = mapView - // Set Configuration - self.configuration = configuration - // Initialize state - self.state = .stopped - // Add application will resign active observer - NotificationCenter.default.addObserver( - self, - selector: #selector(self.applicationWillResignActive), - name: UIApplication.willResignActiveNotification, - object: nil - ) - // Add application did become active observer - NotificationCenter.default.addObserver( - self, - selector: #selector(self.applicationDidBecomeActive), - name: UIApplication.didBecomeActiveNotification, - object: nil - ) - } - - /// Deinit - deinit { - // Stop - self.stop() - // Remove observer - NotificationCenter.default.removeObserver(self) - } - - // MARK: Public API - - /// Start flyover with FlyoverAble object and optional region change animation mode - /// - /// - Parameters: - /// - flyover: The Flyover object (e.g. CLLocationCoordinate2D, CLLocation, MKMapPoint) - open func start(flyover: Flyover) { - // Set flyover - self.flyover = flyover - // Check if applicationState is not active - if UIApplication.shared.applicationState != .active { - // Return out of function - return - } - // Change state - self.state = .started - // Stop current animation - self.animator?.forceStopAnimation() - // Set center coordinate - self.mapCamera.centerCoordinate = flyover.coordinate - // Check if duration is zero or the current mapView camera - // equals nearly the same to the current flyover - if self.mapView?.camera ~~ self.flyover { - // Simply perform flyover as we still looking at the same coordinate - self.performFlyover(flyover) - } else if case .animated(let duration, let curve) = self.configuration.regionChangeAnimation, duration > 0 { - // Apply StartAnimationMode animated - // Initialize start animatior - let startAnimator = UIViewPropertyAnimator( - duration: duration, - curve: curve, - animations: { [weak self] in - // Verify self is available - guard let strongSelf = self else { - // Self isn't available return out of function - return - } - // Set MapView Camera - strongSelf.mapView?.camera = strongSelf.mapCamera - } - ) - // Add completion - startAnimator.setCompletion { [weak self] in - // Start rotation - self?.performFlyover(flyover) - } - // Start animation - startAnimator.startAnimation() - } else { - // No animation should be applied - // Set MapView Camera to look at the coordinate - self.mapView?.camera = self.mapCamera - // Perform flyover - self.performFlyover(flyover) - } - } - - /// Stop flyover - open func stop() { - // Change state - self.state = .stopped - // Unwrap MapView Camera Heading and fractionComplete - guard var heading = self.mapView?.camera.heading, - let fractionComplete = self.animator?.fractionComplete else { - // Force stop animation - self.animator?.forceStopAnimation() - // Clear animator - self.animator = nil - // Return out function - return - } - // Force stop animation - self.animator?.forceStopAnimation() - // Initialize Animator with stop animation - self.animator = UIViewPropertyAnimator( - duration: 0, - curve: self.curve, - animations: { [weak self] in - // Verify self is available - guard let strongSelf = self else { - // Self isn't available return out of function - return - } - // Substract the headingStep from current heading to retrieve start value - heading -= strongSelf.configuration.headingStep - // Initialize the percentage of the compeleted heading step - let percentageCompletedHeadingStep = Double(fractionComplete) * strongSelf.configuration.headingStep - // Set MapCamera Heading - strongSelf.mapCamera.heading = fmod(heading + percentageCompletedHeadingStep, 360) - // Set MapView Camera - strongSelf.mapView?.camera = strongSelf.mapCamera - }) - // Start animation - self.animator?.startAnimation() - // Clear animator as animation is been handeled - self.animator = nil - } - - // MARK: Private API - - /// Perform flyover at the given Flyover coordinate - /// - /// - Parameter flyover: The Flyover object - private func performFlyover(_ flyover: Flyover?) { - // Unwrap Flyover - guard let flyover = flyover else { - // Flyover unavailable return out of function - return - } - // Increase heading by heading step for mapCamera - self.mapCamera.heading = fmod(self.mapCamera.heading + self.configuration.headingStep, 360) - // Initialize UIViewPropertyAnimator - self.animator = UIViewPropertyAnimator( - duration: self.configuration.duration, - curve: self.curve, - animations: { [weak self] in - // Verify self is available - guard let strongSelf = self else { - // Self isn't available return out of function - return - } - // Update MapViewCamera - strongSelf.mapView?.camera = strongSelf.mapCamera - }) - // Add completion - self.animator?.setCompletion { [weak self] in - // Check if flyovers are nearly equal - if self?.flyover ~~ flyover { - // Invoke recursion - self?.performFlyover(flyover) - } - } - // Start Animation - self.animator?.startAnimation() - } - - /// UIApplicationWillResignActive notification handler - @objc private func applicationWillResignActive() { - // Check if current state is not stopped - if self.state != .stopped { - // Stop flyover as application is no longer active - self.stop() - } else { - // Clear Flyover to prevent start on didBecomeActive - self.flyover = nil - } - } - - /// UIApplicationDidBecomeActive notification handler - @objc private func applicationDidBecomeActive() { - // Start if flyover is available - self.flyover.flatMap(self.start) - } - -} - -// MARK: - UIViewPropertyAnimator Extension - -fileprivate extension UIViewPropertyAnimator { - - /// Force Stop Animation - func forceStopAnimation() { - // Stop animation without finishing - self.stopAnimation(true) - } - - /// Convenience function to set the completion with no parameter closure - /// - /// - Parameter completion: The completion closure - func setCompletion(_ completion: @escaping () -> Void) { - // Add completion - self.addCompletion { _ in - // Invoke closure - completion() - } - } - -} diff --git a/Sources/Flyover+Operators.swift b/Sources/Flyover+Operators.swift deleted file mode 100644 index 464d7f3..0000000 --- a/Sources/Flyover+Operators.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// Flyover+Operators.swift -// FlyoverKit -// -// Created by Sven Tiigi on 28.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import Foundation - -infix operator ~~ - -public extension Optional where Wrapped == Flyover { - - /// Compare two given Flyover types - /// - /// - Parameters: - /// - lhs: The left hand side - /// - rhs: The right hand side - /// - Returns: Boolean if the two given Flyover's are exactly equal - static func == (lhs: Flyover?, rhs: Flyover?) -> Bool { - return lhs?.coordinate.latitude == rhs?.coordinate.latitude - && lhs?.coordinate.longitude == rhs?.coordinate.longitude - } - - /// Compare two given Flyover types via rounded latitude and longitude comparison - /// - /// - Parameters: - /// - lhs: The left hand side - /// - rhs: The right hand side - /// - Returns: Boolean if the two given Flyover's are nearly equal (rounded) - static func ~~ (lhs: Flyover?, rhs: Flyover?) -> Bool { - guard let lhs = lhs?.coordinate, let rhs = rhs?.coordinate else { - return false - } - let factor = 1000.0 - return round(lhs.latitude * factor) == round(rhs.latitude * factor) - && round(lhs.longitude * factor) == round(rhs.longitude * factor) - } - -} diff --git a/Sources/Flyover.swift b/Sources/Flyover.swift deleted file mode 100644 index ae922f1..0000000 --- a/Sources/Flyover.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// Flyover.swift -// FlyoverKit -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import MapKit - -// MARK: - Flyover-Protocol - -/// The Flyover Protocol -public protocol Flyover { - /// The flyover coordinate - var coordinate: CLLocationCoordinate2D { get } -} - -// MARK: - CoreLocation Framework Flyover Extensions - -extension CLLocationCoordinate2D: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return self - } - -} - -extension CLCircularRegion: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return self.center - } - -} - -extension CLLocation: Flyover { } - -// MARK: - MapKit Framework Flyover Extensions - -extension MKMapItem: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return self.placemark.coordinate - } - -} - -extension MKMapView: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return self.centerCoordinate - } - -} - -extension MKMapPoint: Flyover {} - -extension MKCoordinateRegion: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return self.center - } - -} - -extension MKMapRect: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return self.origin.coordinate - } - -} - -extension MKCoordinateSpan: Flyover { - - /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return .init(latitude: self.latitudeDelta, longitude: self.longitudeDelta) - } - -} - -extension MKMapCamera: Flyover { - - /// /// The flyover coordinate - public var coordinate: CLLocationCoordinate2D { - return self.centerCoordinate - } - -} - -extension MKShape: Flyover { } - -extension MKPlacemark: Flyover { } diff --git a/Sources/Flyover/Flyover+Animator.swift b/Sources/Flyover/Flyover+Animator.swift new file mode 100644 index 0000000..c3b8fd9 --- /dev/null +++ b/Sources/Flyover/Flyover+Animator.swift @@ -0,0 +1,80 @@ +import UIKit + +// MARK: - Flyover+Animator + +extension Flyover { + + /// A Flyover Animator + final class Animator { + + /// The UIViewPropertyAnimator + private var propertyAnimator: UIViewPropertyAnimator? + + } + +} + +// MARK: - Start + +extension Flyover.Animator { + + /// Start animations + /// - Parameters: + /// - duration: The duration of the animation, in seconds + /// - curve: The UIKit timing curve to apply to the animation + /// - animations: A closure containing the animations + /// - completion: A closure to execute when the animations ends + func start( + duration: TimeInterval, + curve: UIView.AnimationCurve, + animations: @escaping () -> Void, + completion: @escaping () -> Void + ) { + // Initialize a new property animator + let propertyAnimator = UIViewPropertyAnimator( + duration: duration, + curve: curve, + animations: animations + ) + // Add completion + propertyAnimator.addCompletion { [weak self] finalPosition in + // Verify final position is end + guard finalPosition == .end && self?.propertyAnimator != nil else { + // Otherwise return out of function + return + } + // Invoke completion + completion() + } + // Start animation + propertyAnimator.startAnimation() + // Retain property animator + self.propertyAnimator = propertyAnimator + } + +} + +// MARK: - Stop + +extension Flyover.Animator { + + /// Stop animations + /// - Returns: The completion percentage of the animation, if available + @discardableResult + func stop() -> CGFloat? { + // Verify a property animator is available + guard let propertyAnimator = self.propertyAnimator else { + // Otherwise return nil + return nil + } + // Retrieve the completion percentage of the animation + let fractionComplete = propertyAnimator.fractionComplete + // Stop animation + propertyAnimator.stopAnimation(true) + // Clear property animator reference + self.propertyAnimator = nil + // Return fraction completion percentage + return fractionComplete + } + +} diff --git a/Sources/Flyover/Flyover+Configuration+Parameter.swift b/Sources/Flyover/Flyover+Configuration+Parameter.swift new file mode 100644 index 0000000..4739070 --- /dev/null +++ b/Sources/Flyover/Flyover+Configuration+Parameter.swift @@ -0,0 +1,102 @@ +import Foundation +import SwiftUI + +// MARK: - Flyover+Configuration+Parameter + +public extension Flyover.Configuration { + + /// A Flyover Configuration Parameter + struct Parameter { + + // MARK: Properties + + /// A closure to update the Value to a new Value + private let update: (Value) -> Value + + // MARK: Initializer + + /// Creates a new instance of `Flyover.Configuration.Parameter` + /// - Parameter update: A closure to update the Value to a new Value + public init( + _ update: @escaping (Value) -> Value + ) { + self.update = update + } + + /// Creates a new instance of `Flyover.Configuration.Parameter` + /// - Parameter value: The Value + public init(_ value: Value) { + self.init { _ in value } + } + + // MARK: Call as Function + + /// Call `Flyover.Configuration.Parameter` to retrieve/update its Value + /// - Parameter value: The current Value + /// - Returns: The new Value + public func callAsFunction( + _ value: Value + ) -> Value { + self.update(value) + } + + } + +} + +// MARK: - ExpressibleByIntegerLiteral + +extension Flyover.Configuration.Parameter: ExpressibleByIntegerLiteral { + + /// Creates a new instance of `Flyover.Configuration.Parameter` + /// - Parameter value: The Integer literal + public init( + integerLiteral value: Int + ) { + self.init(.init(value)) + } + +} + +// MARK: - ExpressibleByFloatLiteral + +extension Flyover.Configuration.Parameter: ExpressibleByFloatLiteral where Value: _ExpressibleByBuiltinFloatLiteral { + + /// Creates a new instance of `Flyover.Configuration.Parameter` + /// - Parameter value: The Value literal + public init( + floatLiteral value: Value + ) { + self.init(value) + } + +} + +// MARK: - Increment + +public extension Flyover.Configuration.Parameter { + + /// Increment the Parameter Value by a given Value + /// - Parameter value: The Value that should be incremented + static func increment(by value: Value) -> Self { + .init { $0 + value } + } + +} + +// MARK: - Restricted + +public extension Flyover.Configuration.Parameter { + + /// A restricted Parameter in a given Range + /// - Parameters: + /// - parameter: The Parameter + /// - range: The Range + static func restricted( + _ parameter: Self, + in range: ClosedRange + ) -> Self { + .init { max(min(parameter($0), range.upperBound), range.lowerBound) } + } + +} diff --git a/Sources/Flyover/Flyover+Configuration.swift b/Sources/Flyover/Flyover+Configuration.swift new file mode 100644 index 0000000..88511ae --- /dev/null +++ b/Sources/Flyover/Flyover+Configuration.swift @@ -0,0 +1,65 @@ +import CoreLocation +import UIKit + +// MARK: - Flyover+Configuration + +public extension Flyover { + + /// A Flyover Configuration + struct Configuration { + + // MARK: Properties + + /// The animation duration in seconds + public var animationDuration: TimeInterval + + /// The animation curve + public var animationCurve: UIView.AnimationCurve + + /// The altitude above the ground, measured in meters + public var altitude: Parameter + + /// The viewing angle of the camera, measured in degrees + public var pitch: Parameter + + /// The heading of the camera (measured in degrees) relative to true north + public var heading: Parameter + + // MARK: Initializer + + /// Creates a new instance of `Flyover.Configuration` + /// - Parameters: + /// - animationDuration: The animation duration in seconds. Default value `1` + /// - animationCurve: The animation curve. Default value `.linear` + /// - altitude: The altitude above the ground, measured in meters + /// - pitch: The viewing angle of the Flyover, measured in degrees + /// - heading: The heading of the Flyover, measured in degrees, relative to true north + public init( + animationDuration: TimeInterval = 1, + animationCurve: UIView.AnimationCurve = .linear, + altitude: Parameter, + pitch: Parameter, + heading: Parameter + ) { + self.animationDuration = animationDuration + self.animationCurve = animationCurve + self.altitude = altitude + self.pitch = pitch + self.heading = heading + } + } + +} + +// MARK: - Flyover+Configuration+default + +public extension Flyover.Configuration { + + /// A default Flyover Configuration + static let `default` = Self( + altitude: 2000, + pitch: 50, + heading: .increment(by: 1.5) + ) + +} diff --git a/Sources/Flyover/Flyover+Context.swift b/Sources/Flyover/Flyover+Context.swift new file mode 100644 index 0000000..1e08f28 --- /dev/null +++ b/Sources/Flyover/Flyover+Context.swift @@ -0,0 +1,34 @@ +import CoreLocation +import Foundation + +// MARK: - Flyover+Context + +extension Flyover { + + /// A Flyover Context + struct Context { + + /// The CLLocationCoordinate2D + let coordinate: CLLocationCoordinate2D + + /// The Configuration + let configuration: Configuration + + } + +} + +// MARK: - Flyover+Context+matches(with:) + +extension Flyover.Context { + + /// Retrieve a Bool value whether a given Coordinate matches with the current one + /// - Parameter coordinate: The Coordinate to check + func matches( + with coordinate: CLLocationCoordinate2D + ) -> Bool { + self.coordinate.latitude == coordinate.latitude + && self.coordinate.longitude == coordinate.longitude + } + +} diff --git a/Sources/Flyover/Flyover.swift b/Sources/Flyover/Flyover.swift new file mode 100644 index 0000000..5b3f571 --- /dev/null +++ b/Sources/Flyover/Flyover.swift @@ -0,0 +1,182 @@ +import MapKit + +// MARK: - Flyover + +/// A Flyover +public final class Flyover { + + // MARK: Properties + + /// The property animator + private let animator = Animator() + + /// Bool value whether Flyover is currently started or stopped + public private(set) var isStarted = false + + /// The map view + public weak var mapView: MKMapView? + + /// The Context + private var context: Context? + + // MARK: Initializer + + /// Creates a new instance of `Flyover` + /// - Parameters: + /// - mapView: The MKMapView (weakly referenced) + public init( + mapView: MKMapView + ) { + self.mapView = mapView + } + +} + +// MARK: - Start + +public extension Flyover { + + /// Start Flyover + /// - Parameters: + /// - coordinate: The Coordinate + /// - configuration: The Flyover Configuration. Default value `.default` + @discardableResult + func start( + at coordinate: CLLocationCoordinate2D, + configuration: Configuration = .default + ) -> Bool { + // Verify the map view is available and the given coordinate is valid + guard let mapView = self.mapView, CLLocationCoordinate2DIsValid(coordinate) else { + // Stop + self.stop() + // Otherwise return false as Flyover could not be started + return false + } + // Check if coordinate has changed + if self.context?.matches(with: coordinate) == false { + // Change camera to new coordinate without animation + mapView.camera = .init( + lookingAtCenter: coordinate, + fromDistance: mapView.camera.centerCoordinateDistance, + pitch: mapView.camera.pitch, + heading: mapView.camera.heading + ) + } + // Set Context + self.context = .init( + coordinate: coordinate, + configuration: configuration + ) + // Verify is not started + guard !self.isStarted else { + // Otherwise return out of function + return self.isStarted + } + // Start animation + let isStarted = self.startAnimation() + // Update is started state + self.isStarted = isStarted + // Return is started + return isStarted + } + +} + +// MARK: - Start Animation + +private extension Flyover { + + /// Start Animation + @discardableResult + func startAnimation() -> Bool { + // Verify map view and context are available + guard let mapView = self.mapView, + let context = self.context else { + // Otherwise return false as animation could not be started + return false + } + // Start animation + self.animator.start( + duration: context.configuration.animationDuration, + curve: context.configuration.animationCurve, + animations: { [weak mapView] in + // Verify map view is available + guard let mapView = mapView else { + // Otherwise return out of function + return + } + // Update heading + mapView.camera = .init( + lookingAtCenter: context.coordinate, + fromDistance: context.configuration.altitude(mapView.camera.centerCoordinateDistance), + pitch: context.configuration.pitch(mapView.camera.pitch), + heading: fmod( + context.configuration.heading(mapView.camera.heading), + 360 + ) + ) + }, + completion: { [weak self] in + // Restart animation + self?.startAnimation() + } + ) + // Return true as animation was started succesfully + return true + } + +} + +// MARK: - Resume + +public extension Flyover { + + /// Resume Flyover with the latest coordiante and configuration, if available + /// - Returns: A Bool value if the Flyover could be resumed + @discardableResult + func resume() -> Bool { + // Verify is not started + guard !self.isStarted else { + // Otherwise return false as Flyover can not be resumed + return false + } + // Restart animation + return self.startAnimation() + } + +} + +// MARK: - Stop + +public extension Flyover { + + /// Stop Flyover + func stop() { + // Disable is started + self.isStarted = false + // Verify MapView and PropertyAnimator are available + guard let fractionComplete = self.animator.stop(), + let mapView = self.mapView, + let context = self.context else { + // Return out of function + return + } + // Switch on map type + switch mapView.mapType { + case .standard, .mutedStandard: + // Set heading + mapView.camera.heading = fmod( + { + let heading = mapView.camera.heading + let headingDelta = (context.configuration.heading(heading) - heading) + return (heading - headingDelta) + (fractionComplete * headingDelta) + }(), + 360 + ) + default: + // Re-apply the heading to stop any ongoing animations + mapView.camera.heading = mapView.camera.heading + } + } + +} diff --git a/Sources/FlyoverMap/FlyoverMap.swift b/Sources/FlyoverMap/FlyoverMap.swift new file mode 100644 index 0000000..742a540 --- /dev/null +++ b/Sources/FlyoverMap/FlyoverMap.swift @@ -0,0 +1,88 @@ +import MapKit +import SwiftUI + +// MARK: - FlyoverMap + +/// A FlyoverMap +public struct FlyoverMap { + + // MARK: Properties + + /// Bool value if Flyover is started + private let isStarted: Bool + + /// The Coordinate + private let coordinate: CLLocationCoordinate2D + + /// The Flyover Configuration + private let configuration: Flyover.Configuration + + /// The MapType + private let mapType: MKMapType + + /// A closure to update the underlying FlyoverMapView + private let updateMapView: ((FlyoverMapView) -> Void)? + + // MARK: Initializer + + /// Creates a new instance of `FlyoverMap` + /// - Parameters: + /// - isStarted: Bool value if Flyover is started. Default value `true` + /// - coordinate: The Coordinate + /// - configuration: The Flyover Configuration. Default value `.default` + /// - mapView: The MapType. Default value `.standard` + /// - updateMapView: A closure to update the underlying FlyoverMapView. Default value `nil` + public init( + isStarted: Bool = true, + coordinate: CLLocationCoordinate2D, + configuration: Flyover.Configuration = .default, + mapType: MKMapType = .standard, + updateMapView: ((FlyoverMapView) -> Void)? = nil + ) { + self.isStarted = isStarted + self.coordinate = coordinate + self.configuration = configuration + self.mapType = mapType + self.updateMapView = updateMapView + } + +} + +// MARK: - UIViewRepresentable + +extension FlyoverMap: UIViewRepresentable { + + /// Make MKMapView + /// - Parameter context: The Context + public func makeUIView( + context: Context + ) -> FlyoverMapView { + .init() + } + + /// Update MKMapView + /// - Parameters: + /// - flyoverMapView: The FlyoverMapView + /// - context: The Context + public func updateUIView( + _ flyoverMapView: FlyoverMapView, + context: Context + ) { + // Update map type + flyoverMapView.mapType = self.mapType + // Update map view if needed + self.updateMapView?(flyoverMapView) + // Check if is started + if self.isStarted { + // Start Flyover + flyoverMapView.startFlyover( + at: self.coordinate, + configuration: self.configuration + ) + } else { + // Stop Flyover + flyoverMapView.stopFlyover() + } + } + +} diff --git a/Sources/FlyoverMapView/FlyoverMapView.swift b/Sources/FlyoverMapView/FlyoverMapView.swift new file mode 100644 index 0000000..4970fe9 --- /dev/null +++ b/Sources/FlyoverMapView/FlyoverMapView.swift @@ -0,0 +1,128 @@ +import MapKit + +// MARK: - FlyoverMapView + +/// A Flyover capable `MKMapView` +open class FlyoverMapView: MKMapView { + + // MARK: Properties + + /// The Flyover + public private(set) lazy var flyover = Flyover(mapView: self) + + /// The type of data displayed by the map view.s + open override var mapType: MKMapType { + get { + super.mapType + } + set { + super.mapType = { + switch newValue { + case .satellite: + return .satelliteFlyover + case .hybrid: + return .hybridFlyover + default: + return newValue + } + }() + } + } + + // MARK: Initializer + + /// Creates a new instance of `FlyoverMapView` + /// - Parameter frame: The frame rectangle for the view, measured in points + public override init( + frame: CGRect + ) { + super.init(frame: frame) + #if !os(tvOS) + self.showsCompass = false + #endif + self.pointOfInterestFilter = .excludingAll + self.showsBuildings = true + self.showsScale = false + self.isZoomEnabled = false + self.isPitchEnabled = false + self.isScrollEnabled = false + self.isRotateEnabled = false + } + + /// Initializer with NSCoder is unavailable + @available(*, unavailable, message: "Initializer with NSCoder is unavailable") + public required init?(coder: NSCoder) { nil } + +} + +// MARK: - FlyoverMapView+init(mapType:) + +public extension FlyoverMapView { + + /// Creates a new instance of `FlyoverMapView` + /// - Parameter flyoverMapType: The FlyoverMapType + convenience init( + mapType: MKMapType + ) { + self.init(frame: .zero) + self.mapType = mapType + } + +} + +// MARK: - Is Flyover Started + +public extension FlyoverMapView { + + /// Bool value whether Flyover is currently started or stopped + var isFlyoverStarted: Bool { + self.flyover.isStarted + } + +} + +// MARK: - Start Flyover + +public extension FlyoverMapView { + + /// Start Flyover + /// - Parameters: + /// - coordinate: The Coordinate + /// - configuration: The Flyover Configuration. Default value `.default` + @discardableResult + func startFlyover( + at coordinate: CLLocationCoordinate2D, + configuration: Flyover.Configuration = .default + ) -> Bool { + self.flyover.start( + at: coordinate, + configuration: configuration + ) + } + +} + +// MARK: - Resume Flyover + +public extension FlyoverMapView { + + /// Resume Flyover with the latest coordiante and configuration, if available + /// - Returns: A Bool value if the Flyover could be resumed + @discardableResult + func resumeFlyover() -> Bool { + self.flyover.resume() + } + +} + + +// MARK: - Stop Flyover + +public extension FlyoverMapView { + + /// Stop Flyover + func stopFlyover() { + self.flyover.stop() + } + +} diff --git a/Sources/MapView/FlyoverMapView+MapType.swift b/Sources/MapView/FlyoverMapView+MapType.swift deleted file mode 100644 index 0863517..0000000 --- a/Sources/MapView/FlyoverMapView+MapType.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// FlyoverMapView+MapType.swift -// FlyoverKit -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import MapKit - -// MARK: - MapType - -public extension FlyoverMapView { - - /// The FlyoverMapView supported MapType - enum MapType: String, Equatable, Hashable, CaseIterable { - /// Standard - case standard - /// Satellite Flyover - case satelliteFlyover - /// Hybrid Flyover - case hybridFlyover - } - -} - -// MARK: - MapType RawRepresentable - -extension FlyoverMapView.MapType: RawRepresentable { - - /// Associated type RawValue as MKMapType - public typealias RawValue = MKMapType - - /// RawRepresentable initializer - /// - /// - Parameters: - /// - rawValue: The MapType - public init?(rawValue: RawValue) { - // Switch on rawValue - switch rawValue { - case .standard: - self = .standard - case .satelliteFlyover: - self = .satelliteFlyover - case .hybridFlyover: - self = .hybridFlyover - default: - return nil - } - } - - /// The MKMapType - public var rawValue: RawValue { - // Switch on self - switch self { - case .standard: - return .standard - case .satelliteFlyover: - return .satelliteFlyover - case .hybridFlyover: - return .hybridFlyover - } - } - -} diff --git a/Sources/MapView/FlyoverMapView.swift b/Sources/MapView/FlyoverMapView.swift deleted file mode 100644 index aa8afaa..0000000 --- a/Sources/MapView/FlyoverMapView.swift +++ /dev/null @@ -1,118 +0,0 @@ -// -// FlyoverMapView.swift -// FlyoverKit -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import MapKit - -// MARK: - FlyoverMapView - -/// The FlyoverMapView -open class FlyoverMapView: MKMapView { - - // MARK: Properties - - /// The FlyoverCamera - open lazy var flyoverCamera: FlyoverCamera = { - return FlyoverCamera(mapView: self) - }() - - /// The FlyoverMapView MapType - open var flyoverMapType: MapType? { - get { - // Return MapType constructed with MKMapType otherwise return standard - return MapType(rawValue: self.mapType) - } - set { - // Set mapType rawValue - newValue.flatMap { self.mapType = $0.rawValue } - } - } - - /// The FlyoverCamera Configuration computed property for easy access - open var configuration: FlyoverCamera.Configuration { - get { - // Return FlyoverCamera configuration - return self.flyoverCamera.configuration - } - set { - // Set new value - self.flyoverCamera.configuration = newValue - } - } - - /// Retrieve FlyoverCamera state - open var state: FlyoverCamera.State { - // Return FlyoverCamera state property - return self.flyoverCamera.state - } - - // MARK: Initializer - - /// Default initializer with flyover configuration and map type - /// - /// - Parameters: - /// - configuration: The flyover configuration. Default value: `.default` theme - /// - mapType: The map type. Default value: `.standard` type - public init(configuration: FlyoverCamera.Configuration = .default, - mapType: MapType = .standard) { - super.init(frame: .zero) - // Set the configuration - self.flyoverCamera.configuration = configuration - // Set flyover map type - self.flyoverMapType = mapType - // Hide compass on iOS - #if os(iOS) - self.showsCompass = false - #endif - // Show buildings - self.showsBuildings = true - } - - /// Initializer with NSCoder (not supported) returns nil - required public init?(coder aDecoder: NSCoder) { - return nil - } - - /// Deinit - deinit { - // Stop FlyoverCamera - self.stop() - } - - // MARK: Convenience start/stop functions - - /// Start flyover with MKAnnotation and the optional region change animation mode. - /// - /// - Parameters: - /// - annotation: The MKAnnotation - open func start(annotation: MKAnnotation) { - // Disable userInteraction - self.isUserInteractionEnabled = false - // Start flyover with annotation coordinate - self.start(flyover: annotation.coordinate) - } - - /// Start flyover with FlyoverAble and the optional region change animation mode. - /// - /// - Parameters: - /// - flyover: The Flyover object (e.g. CLLocationCoordinate2D, CLLocation, MKMapPoint) - open func start(flyover: Flyover) { - // Disable userInteraction - self.isUserInteractionEnabled = false - // Start flyover - self.flyoverCamera.start(flyover: flyover) - } - - /// Stop Flyover - open func stop() { - // Stop FlyoverCamera - self.flyoverCamera.stop() - // Enable userInteraction - self.isUserInteractionEnabled = true - } - -} diff --git a/Sources/MapView/FlyoverMapViewController.swift b/Sources/MapView/FlyoverMapViewController.swift deleted file mode 100644 index 4e2ae6c..0000000 --- a/Sources/MapView/FlyoverMapViewController.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// FlyoverMapViewController.swift -// FlyoverKit -// -// Created by Sven Tiigi on 21.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import UIKit - -// MARK: - FlyoverMapViewController - -/// The FlyoverMapViewController -open class FlyoverMapViewController: UIViewController { - - // MARK: Properties - - /// The flyover MapView - open var flyoverMapView: FlyoverMapView - - /// The flyover - open var flyover: Flyover { - didSet { - // Start Flyover - self.flyoverMapView.start(flyover: flyover) - } - } - - // MARK: Initializer - - /// Default initializer with flyover configuration and map type - /// - /// - Parameters: - /// - flyover: The flyover object - /// - configuration: The flyover configuration. Default value: `.default` theme - /// - mapType: The map type. Default value `.standard` type - public init(flyover: Flyover, - configuration: FlyoverCamera.Configuration = .default, - mapType: FlyoverMapView.MapType = .standard) { - self.flyoverMapView = FlyoverMapView(configuration: configuration, mapType: mapType) - self.flyover = flyover - super.init(nibName: nil, bundle: nil) - self.flyoverMapView.start(flyover: flyover) - } - - /// Initializer with NSCoder. Returns nil - required public init?(coder aDecoder: NSCoder) { - return nil - } - - /// Deinit - deinit { - // Stop flyover - self.flyoverMapView.stop() - } - - // MARK: View-Lifecycle - - /// LoadView - open override func loadView() { - // Set FlyoverMapView as underlying view - self.view = self.flyoverMapView - } - -} diff --git a/Tests/BaseTests.swift b/Tests/BaseTests.swift deleted file mode 100644 index 80ffd30..0000000 --- a/Tests/BaseTests.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// BaseTests.swift -// FlyoverKitTests -// -// Created by Sven Tiigi on 24.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import CoreLocation -@testable import FlyoverKit -import XCTest - -// MARK: - BaseTests - -/// The BaseTests -class BaseTests: XCTestCase { - - /// The timeout value while waiting - /// that an expectation is fulfilled - let expectationTimeout: TimeInterval = 10.0 - - /// Random Double Value - var randomDouble: Double { - let random = Double(arc4random()) / 0xFFFFFFFF - return random * (80 - 10) + 10 - } - - /// Random CLLocationCoordinate2D - var randomCoordinate: CLLocationCoordinate2D { - return CLLocationCoordinate2D(latitude: self.randomDouble, longitude: self.randomDouble) - } - - /// SetUp - override func setUp() { - super.setUp() - // Disable continueAfterFailure - self.continueAfterFailure = false - } - - /// Perform test with expectation - /// - /// - Parameters: - /// - name: The expectation name - /// - execution: The test execution - func performTest(_ expectationName: String, _ timeout: TimeInterval? = nil, - _ execution: (XCTestExpectation) -> Void) { - // Create expectation with function name - let expectation = self.expectation(description: expectationName) - // Perform test execution with expectation - execution(expectation) - // Wait for expectation been fulfilled with custom or default timeout - self.waitForExpectations(timeout: timeout.flatMap { $0 } ?? self.expectationTimeout, handler: nil) - } - -} - -// MARK: - XCTestCase AssertFlyover - -extension XCTestCase { - - /// Assert that two given Flyover objects are equal by comparing latitude and longitude - /// - /// - Parameters: - /// - flyover1: The first Flyover object - /// - flyover2: The second Flyover object - func XCTAssertFlyover(_ flyover1: Flyover, _ flyover2: Flyover) { - // Assert Flyover - XCTAssertTrue(flyover1 == flyover2) - } - -} diff --git a/Tests/FlyoverCameraTests.swift b/Tests/FlyoverCameraTests.swift deleted file mode 100644 index bb200c0..0000000 --- a/Tests/FlyoverCameraTests.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// FlyoverCameraTests.swift -// FlyoverKitTests -// -// Created by Sven Tiigi on 24.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -@testable import FlyoverKit -import MapKit -import XCTest - -class FlyoverCameraTests: BaseTests { - - func testConfigurationEquatable() { - let duration = 1.0 - let altitude = 2.0 - let pitch = 3.0 - let headingStep = 4.0 - let configuration1 = FlyoverCamera.Configuration( - duration: duration, - altitude: altitude, - pitch: pitch, - headingStep: headingStep - ) - let configuration2 = FlyoverCamera.Configuration( - duration: duration, - altitude: altitude, - pitch: pitch, - headingStep: headingStep - ) - XCTAssertEqual(configuration1, configuration2) - } - - func testFlyoverCameraDefaultInitializerConfiguration() { - let mapView = MKMapView() - let flyoverCamera = FlyoverCamera(mapView: mapView) - XCTAssertEqual(flyoverCamera.configuration, .default) - } - - func testFlyoverCameraConfigurationTheme() { - let mapView = MKMapView() - let configurationThemes: [FlyoverCamera.Configuration] = [ - .default, - .lowFlying, - .farAway, - .giddy, - .astronautView - ] - configurationThemes.forEach { (theme) in - let flyoverCamera = FlyoverCamera(mapView: mapView, configuration: theme) - XCTAssertEqual(flyoverCamera.configuration, theme) - } - } - - func testFlyoverCameraStartStop() { - let mapView = MKMapView() - let flyoverCamera = FlyoverCamera(mapView: mapView) - XCTAssertFalse(flyoverCamera.state == .started) - flyoverCamera.start(flyover: FlyoverAwesomePlace.parisEiffelTower) - XCTAssertTrue(flyoverCamera.state == .started) - flyoverCamera.stop() - XCTAssertFalse(flyoverCamera.state == .started) - flyoverCamera.configuration.regionChangeAnimation = .animated(duration: 0.1, curve: .linear) - flyoverCamera.configuration.duration = 0.1 - flyoverCamera.start(flyover: FlyoverAwesomePlace.parisEiffelTower) - self.performTest(#function) { (expectation) in - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: { - XCTAssertTrue(flyoverCamera.state == .started) - flyoverCamera.start(flyover: FlyoverAwesomePlace.googlePlex) - XCTAssertTrue(flyoverCamera.state == .started) - flyoverCamera.stop() - XCTAssertFalse(flyoverCamera.state == .started) - expectation.fulfill() - }) - } - } - -} diff --git a/Tests/FlyoverMapViewTests.swift b/Tests/FlyoverMapViewTests.swift deleted file mode 100644 index a287aa3..0000000 --- a/Tests/FlyoverMapViewTests.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// FlyoverMapViewTests.swift -// FlyoverKitTests -// -// Created by Sven Tiigi on 24.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -@testable import FlyoverKit -import MapKit -import XCTest - -class FlyoverMapViewTests: BaseTests { - - // MARK: FlyoverMapView - - func testFlyoverMapViewDefaultInitializer() { - let mapView = FlyoverMapView() - XCTAssertEqual(mapView.configuration, .default) - XCTAssertEqual(mapView.flyoverMapType, .standard) - } - - func testFlyoverMapViewConvenienceInitializer() { - let theme: FlyoverCamera.Configuration = .farAway - let mapType: FlyoverMapView.MapType = .satelliteFlyover - let mapView = FlyoverMapView(configuration: theme, mapType: mapType) - XCTAssertEqual(mapView.configuration, theme) - XCTAssertEqual(mapView.flyoverMapType, mapType) - } - - func testFlyoverMapViewStartStop() { - let mapView = FlyoverMapView() - XCTAssertFalse(mapView.state == .started) - mapView.start(flyover: FlyoverAwesomePlace.appleHeadquarter) - XCTAssertTrue(mapView.state == .started) - mapView.stop() - XCTAssertFalse(mapView.state == .started) - let annotation = MKPointAnnotation() - annotation.coordinate = self.randomCoordinate - mapView.start(annotation: annotation) - XCTAssertTrue(mapView.state == .started) - mapView.stop() - XCTAssertFalse(mapView.state == .started) - } - - func testFlyoverMapViewMapType() { - let standard: FlyoverMapView.MapType = .standard - let satelliteFlyover: FlyoverMapView.MapType = .satelliteFlyover - let hybridFlyover: FlyoverMapView.MapType = .hybridFlyover - XCTAssertEqual(MKMapType.standard, standard.rawValue) - XCTAssertEqual(MKMapType.satelliteFlyover, satelliteFlyover.rawValue) - XCTAssertEqual(MKMapType.hybridFlyover, hybridFlyover.rawValue) - XCTAssertEqual([ - MKMapType.standard, - MKMapType.satelliteFlyover, - MKMapType.hybridFlyover - ].map(FlyoverMapView.MapType.init).count, 3) - XCTAssertNil(FlyoverMapView.MapType.init(rawValue: .satellite)) - let mapView = FlyoverMapView() - mapView.flyoverMapType = satelliteFlyover - XCTAssertNotNil(mapView.flyoverMapType) - XCTAssertEqual(mapView.flyoverMapType, satelliteFlyover) - XCTAssertEqual(mapView.mapType, .satelliteFlyover) - mapView.mapType = .satellite - XCTAssertNil(mapView.flyoverMapType) - } - - func testFlyoverMapViewConfigurationUpdate() { - let flyoverMapView = FlyoverMapView() - let configuration: FlyoverCamera.Configuration = .farAway - flyoverMapView.configuration = configuration - XCTAssertEqual(configuration, flyoverMapView.configuration) - } - - // MARK: FlyoverMapViewController - - func testFlyoverMapViewController() { - var flyover = FlyoverAwesomePlace.appleHeadquarter - let controller = FlyoverMapViewController(flyover: flyover) - XCTAssertFlyover(flyover, controller.flyover) - XCTAssertEqual(controller.view, controller.flyoverMapView) - XCTAssertTrue(controller.flyoverMapView.state == .started) - XCTAssertEqual(controller.flyoverMapView.configuration, .default) - XCTAssertEqual(controller.flyoverMapView.flyoverMapType, .standard) - flyover = FlyoverAwesomePlace.googlePlex - controller.flyover = flyover - XCTAssertFlyover(flyover, controller.flyover) - XCTAssertTrue(controller.flyoverMapView.state == .started) - } - - func testFlyoverMapViewControllerThemeInitializer() { - let flyover = FlyoverAwesomePlace.googlePlex - let controller = FlyoverMapViewController( - flyover: flyover, - configuration: .farAway, mapType: .satelliteFlyover - ) - XCTAssertFlyover(flyover, controller.flyover) - XCTAssertEqual(controller.flyoverMapView.configuration, .farAway) - XCTAssertEqual(controller.flyoverMapView.flyoverMapType, .satelliteFlyover) - } - -} diff --git a/Tests/FlyoverProtocolTests.swift b/Tests/FlyoverProtocolTests.swift deleted file mode 100644 index 4d93cc0..0000000 --- a/Tests/FlyoverProtocolTests.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// FlyoverProtocolTests.swift -// FlyoverKitTests -// -// Created by Sven Tiigi on 24.02.18. -// Copyright © 2018 Sven Tiigi. All rights reserved. -// - -import CoreLocation -@testable import FlyoverKit -import MapKit -import XCTest - -class FlyoverProtocolTests: BaseTests { - - func testFlyoverOperator() { - let flyover1: Flyover = self.randomCoordinate - let flyover2: Flyover? = flyover1 - let flyover3: Flyover = self.randomCoordinate - let flyover4: Flyover? = nil - let flyover5: Flyover? = flyover3 - XCTAssertTrue(flyover1 == flyover2) - XCTAssertTrue(flyover1 ~~ flyover2) - XCTAssertFalse(flyover1 == flyover4) - XCTAssertFalse(flyover2 ~~ flyover4) - XCTAssertFalse(flyover1 == flyover3) - XCTAssertFalse(flyover2 ~~ flyover3) - XCTAssertFalse(flyover3 == flyover4) - XCTAssertFalse(flyover3 ~~ flyover4) - XCTAssertTrue(flyover3 == flyover5) - XCTAssertTrue(flyover3 ~~ flyover5) - } - - func testFlyoverCLLocationCoordinate2D() { - let coordinate = self.randomCoordinate - XCTAssertFlyover(coordinate, coordinate.coordinate) - } - - func testFlyoverCLCircularRegion() { - let coordinate = self.randomCoordinate - let region = CLCircularRegion(center: coordinate, radius: 300, identifier: "") - XCTAssertFlyover(coordinate, region) - } - - func testFlyoverMKMapItem() { - let coordinate = self.randomCoordinate - let mapItem = MKMapItem(placemark: MKPlacemark(coordinate: coordinate)) - XCTAssertFlyover(coordinate, mapItem) - } - - func testFlyoverMKMapPoint() { - let mockValue = (x: self.randomDouble, y: self.randomDouble) - let mapPoint = MKMapPoint(x: mockValue.x, y: mockValue.y) - let coordinate = mapPoint.coordinate - XCTAssertFlyover(mapPoint, coordinate) - } - - func testFlyoverMKCoorindateRegionAndSpan() { - let coordinate = self.randomCoordinate - let span = MKCoordinateSpan(latitudeDelta: coordinate.latitude, longitudeDelta: coordinate.longitude) - let region = MKCoordinateRegion(center: coordinate, span: span) - XCTAssertFlyover(coordinate, region) - XCTAssertFlyover(coordinate, span) - } - - func testFlyoverMapView() { - let mapView = MKMapView() - let coordinate = mapView.centerCoordinate - XCTAssertFlyover(coordinate, mapView) - } - - func testFlyoverMKMapRect() { - let mockValue = (x: self.randomDouble, y: self.randomDouble) - let mapPoint = MKMapPoint(x: mockValue.x, y: mockValue.y) - let coordinate = mapPoint.coordinate - let rect = MKMapRect(origin: mapPoint, size: MKMapSize(width: mockValue.x, height: mockValue.y)) - XCTAssertFlyover(coordinate, rect) - } - - func testFlyoverMKMapCamera() { - let coordinate = self.randomCoordinate - let camera = MKMapCamera() - camera.centerCoordinate = coordinate - XCTAssertFlyover(coordinate, camera) - } - - func testFlyoverAwesomePlaceCases() { - for place in FlyoverAwesomePlace.allCases { - XCTAssertFlyover(place, place.coordinate) - } - for place in FlyoverAwesomePlace.iterate() { - XCTAssertFlyover(place, place.coordinate) - } - } - -} diff --git a/fastlane/.env b/fastlane/.env deleted file mode 100644 index ef9bcc7..0000000 --- a/fastlane/.env +++ /dev/null @@ -1 +0,0 @@ -FASTLANE_SKIP_UPDATE_CHECK=1 diff --git a/fastlane/Fastfile b/fastlane/Fastfile deleted file mode 100644 index 2b28672..0000000 --- a/fastlane/Fastfile +++ /dev/null @@ -1,98 +0,0 @@ -fastlane_version "2.120.0" - -default_platform :ios - -platform :ios do - - desc "Release a new version of FlyoverKit" - lane :release do |options| - # Ensure Git status is clean - ensure_git_status_clean - # Ensure Git branch is master - ensure_git_branch(branch: 'master') - # Perform Dependency-Manager compatibility tests - compatibilityTests - # Perform Tests - tests - # Retrieve Version from options - version = options[:version] - # Increment Version - increment(version: version) - # Add Git Tag - add_git_tag(tag: version) - # Push Git Tag - push_git_tags() - # Push Git commit - push_to_git_remote() - # Pod push / Pod trunk - pod_push() - end - - desc "Increment Version" - lane :increment do |options| - # Retrieve Version from options - version = options[:version] - # Set Podspec version - version_bump_podspec( - path: "FlyoverKit.podspec", - version_number: version - ) - # Set Framework plist version - set_info_plist_value( - path: "Configs/FlyoverKit.plist", - key: "CFBundleShortVersionString", - value: version - ) - # Set Framework Tests plist version - set_info_plist_value( - path: "Configs/FlyoverKitTests.plist", - key: "CFBundleShortVersionString", - value: version - ) - # Set Example plist version - set_info_plist_value( - path: "Example/Resources/Info.plist", - key: "CFBundleShortVersionString", - value: version - ) - # Commit modified files - git_commit( - path: [ - "FlyoverKit.podspec", - "Configs/FlyoverKit.plist", - "Configs/FlyoverKitTests.plist", - "Example/Resources/Info.plist" - ], - message: "FlyoverKit Version #{version} 🚀" - ) - end - - desc "Runs tests" - lane :tests do - # Perform iOS Tests - scan( - project: "FlyoverKit.xcodeproj", - scheme: "FlyoverKit-iOS", - clean: true - ) - # Perform tvOS Tests - scan( - project: "FlyoverKit.xcodeproj", - scheme: "FlyoverKit-tvOS", - clean: true - ) - end - - desc "Run Dependency-Manager compatibility tests" - lane :compatibilityTests do - # Carthage build to ensure Carthage compatibility - carthage( - command: "build", - no_skip_current: true, - cache_builds: true - ) - # Pod lib lint to ensure CocoaPods compatibility - pod_lib_lint(allow_warnings: true) - end - -end