├── Cartfile ├── Gemfile ├── .travis.yml ├── .gitignore ├── fastlane ├── Fastfile └── Appfile ├── MTGSDKSwift.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── reedcarson.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ ├── MTGSDKSwiftTests.xcscheme │ │ └── MTGSDKSwift.xcscheme └── project.pbxproj ├── MTGSDKSwift ├── Models │ ├── NetworkError.swift │ ├── CardSet.swift │ ├── MTGSearchConfiguration.swift │ ├── Constants.swift │ ├── SearchParameter.swift │ └── Card.swift ├── MTGSDKSwift.h ├── Info.plist ├── URLBuilder.swift ├── MTGAPIService.swift └── MagicalCardManager.swift ├── TestApplication ├── AppDelegate.swift ├── ViewController.swift ├── Info.plist ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard └── Assets.xcassets │ └── AppIcon.appiconset │ └── Contents.json ├── .github └── PULL_REQUEST_TEMPLATE.MD ├── MTGSDKSwiftTests ├── Info.plist ├── MTGSDKSwiftTests.swift └── Resources │ └── karn.json ├── Package.swift ├── MTGSDKSwift.podspec ├── LICENSE ├── Gemfile.lock └── README.md /Cartfile: -------------------------------------------------------------------------------- 1 | github "MagicTheGathering/mtg-sdk-swift" ~> 0.1 2 | 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode10 3 | script: 4 | - bundle exec fastlane test 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | xcuserdata 4 | 5 | # Fastlane 6 | fastlane/README.md 7 | fastlane/report.xml 8 | fastlane/test_output/ 9 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | 2 | update_fastlane 3 | 4 | default_platform(:ios) 5 | 6 | platform :ios do 7 | desc "Runs the tests" 8 | lane :test do 9 | scan(scheme: 'MTGSDKSwift') 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /MTGSDKSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MTGSDKSwift.xcodeproj/xcuserdata/reedcarson.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | # app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app 2 | # apple_id("[[APPLE_ID]]") # Your Apple email address 3 | 4 | 5 | # For more information about the Appfile, see: 6 | # https://docs.fastlane.tools/advanced/#appfile 7 | -------------------------------------------------------------------------------- /MTGSDKSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MTGSDKSwift/Models/NetworkError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkError.swift 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 3/3/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum NetworkError: Error { 12 | case requestError(Error) 13 | case unexpectedHTTPResponse(HTTPURLResponse) 14 | case fetchCardImageError(String) 15 | case miscError(String) 16 | case decodableError(Error) 17 | } 18 | -------------------------------------------------------------------------------- /MTGSDKSwift/MTGSDKSwift.h: -------------------------------------------------------------------------------- 1 | // 2 | // MTGSDKSwift.h 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 2/27/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for MTGSDKSwift. 12 | FOUNDATION_EXPORT double MTGSDKSwiftVersionNumber; 13 | 14 | //! Project version string for MTGSDKSwift. 15 | FOUNDATION_EXPORT const unsigned char MTGSDKSwiftVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /TestApplication/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TestApplication 4 | // 5 | // Created by Reed Carson on 3/14/18. 6 | // Copyright © 2018 Reed Carson. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /MTGSDKSwift/Models/CardSet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardSet.swift 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 2/27/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct CardSet: Decodable { 12 | public init() {} 13 | 14 | public var code: String? 15 | public var name: String? 16 | public var block: String? 17 | public var type: String? 18 | public var border: String? 19 | public var releaseDate: String? 20 | public var magicCardsInfoCode: String? 21 | public var booster: [[String]]? 22 | } 23 | 24 | public struct SetsResponse: ResponseObject, Decodable { 25 | public var sets: [CardSet] 26 | } 27 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.MD: -------------------------------------------------------------------------------- 1 | ### Background 2 | Describe the purpose of this pull request. 3 | 4 | ### Breaking Changes 5 | Describe any breaking changes that this pull request will introduce. 6 | 7 | 8 | ### Checklist 9 | 10 | - [ ] Appropriate label has been added to this PR (i.e., Bug, Enhancement, etc.). 11 | - [ ] Documentation has been added to all `open`, `public`, and `internal` scoped methods and properties. 12 | - [ ] Tests have have been added to all new features. 13 | - [ ] Image/GIFs have been added for all UI related changed. 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /MTGSDKSwiftTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /MTGSDKSwift/Models/MTGSearchConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MTGSearchConfiguration.swift 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 4/16/18. 6 | // Copyright © 2018 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct MTGSearchConfiguration { 12 | public static var defaultConfiguration: MTGSearchConfiguration { 13 | return MTGSearchConfiguration(pageSize: Int(Constants.defaultPageSize) ?? 12, 14 | pageTotal: Int(Constants.defaultPageTotal) ?? 1) 15 | } 16 | 17 | public let pageSize: Int 18 | public let pageTotal: Int 19 | 20 | public init(pageSize: Int, pageTotal: Int) { 21 | self.pageSize = pageSize 22 | self.pageTotal = pageTotal 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.5 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "MTGSDKSwift", 8 | platforms: [ 9 | .iOS(.v15), 10 | .macOS(.v12) 11 | ], 12 | products: [ 13 | .library( 14 | name: "MTGSDKSwift", 15 | targets: ["MTGSDKSwift"]), 16 | ], 17 | dependencies: [], 18 | targets: [ 19 | .target( 20 | name: "MTGSDKSwift", 21 | dependencies: [], 22 | path: "MTGSDKSwift" 23 | ), 24 | .testTarget( 25 | name: "MTGSDKSwiftTests", 26 | dependencies: [], 27 | path: "MTGSDKSwiftTests" 28 | ), 29 | ] 30 | ) 31 | -------------------------------------------------------------------------------- /MTGSDKSwift.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint mtg-sdk-swift.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | 6 | Pod::Spec.new do |s| 7 | s.name = 'MTGSDKSwift' 8 | s.version = '1.1.1' 9 | s.summary = 'Magic: The Gathering SDK - Swift' 10 | s.description = <<-DESC 11 | A lightweight framework that makes interacting with the magicthegathering.io api quick, easy and safe. 12 | DESC 13 | 14 | s.homepage = 'https://github.com/MagicTheGathering/mtg-sdk-swift' 15 | s.license = { :type => 'MIT', :file => 'LICENSE' } 16 | s.author = { 'Reed Carson' => 'rpcarson27@gmail.com' } 17 | s.source = { :git => 'https://github.com/MagicTheGathering/mtg-sdk-swift.git', :tag => s.version.to_s } 18 | 19 | s.ios.deployment_target = '10.2' 20 | s.osx.deployment_target = '12.4' 21 | s.source_files = 'MTGSDKSwift/**/*.swift' 22 | s.swift_version = '4.1' 23 | end 24 | -------------------------------------------------------------------------------- /MTGSDKSwift.xcodeproj/xcuserdata/reedcarson.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MTGSDKSwift.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | MTGSDKSwiftTests.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | TestApplication.xcscheme 18 | 19 | orderHint 20 | 1 21 | 22 | TestApplication.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 2 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 5BD04DB11E64943C00E5ED27 31 | 32 | primary 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Reed Carson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MTGSDKSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSAppTransportSecurity 22 | 23 | NSExceptionDomains 24 | 25 | wizards.com 26 | 27 | NSIncludesSubdomains 28 | 29 | NSTemporaryExceptionAllowsInsecureHTTPLoads 30 | 31 | NSTemporaryExceptionMinimumTLSVersion 32 | TLSv1.1 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /TestApplication/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TestApplication 4 | // 5 | // Created by Reed Carson on 3/14/18. 6 | // Copyright © 2018 Reed Carson. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MTGSDKSwift 11 | 12 | class ViewController: UIViewController { 13 | 14 | let magic = Magic() 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | let color = CardSearchParameter(parameterType: .colors, value: "black") 20 | let type = CardSearchParameter(parameterType: .type, value: "planeswalker") 21 | let loyal = CardSearchParameter(parameterType: .loyalty, value: "5") 22 | let legal = CardSearchParameter(parameterType: .legality, value: "Banned") 23 | let config = MTGSearchConfiguration(pageSize: 60, pageTotal: 1) 24 | 25 | magic.fetchCards([color], configuration: config) { (result) in 26 | switch result { 27 | case .error(let error): 28 | print(error.localizedDescription) 29 | case .success(let cards): 30 | print("CARDS COUNT: \(cards.count)") 31 | for c in cards { 32 | print("Card: \(c) \n") 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /MTGSDKSwift/Models/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 4/16/18. 6 | // Copyright © 2018 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Constants { 12 | static let baseEndpoint = "https://api.magicthegathering.io/v1" 13 | static let generateBoosterPath = "/booster" 14 | static let cardsEndpoint = "/v1/cards" 15 | static let setsEndpoint = "/v1/sets" 16 | static let host = "api.magicthegathering.io" 17 | static let scheme = "https" 18 | static let defaultPageSize = "12" 19 | static let defaultPageTotal = "1" 20 | } 21 | 22 | /// If logging is enabled, this function performs debug logging to the console for you with the 23 | /// context of where it came from. 24 | /// ## Example 25 | /// ``` 26 | /// [MTGAPIService.swift:67:performOperation(completion:)]: MTGSDK HTTPResponse - status code: 200 27 | /// ``` 28 | /// 29 | /// - Parameters: 30 | /// - message: The message you'd like logged. 31 | /// - file: The message source code file. 32 | /// - function: The message source function. 33 | /// - line: The message source line. 34 | func debugPrint(_ message: String, file: String = #file, function: String = #function, line: Int = #line ) { 35 | guard Magic.enableLogging else { 36 | return 37 | } 38 | print("[\((file as NSString).lastPathComponent):\(line):\(function)]: \(message)") 39 | } 40 | -------------------------------------------------------------------------------- /MTGSDKSwift/Models/SearchParameter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchParameter.swift 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 2/27/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public class SearchParameter { 13 | public var name: String = "" 14 | public var value: String = "" 15 | } 16 | 17 | public final class CardSearchParameter: SearchParameter { 18 | 19 | public enum CardQueryParameterType: String { 20 | case name 21 | case cmc 22 | case colors 23 | case contains 24 | case type 25 | case supertypes 26 | case subtypes 27 | case rarity 28 | case text 29 | case set 30 | case artist 31 | case power 32 | case toughness 33 | case multiverseid 34 | case gameFormat 35 | case loyalty 36 | case legality 37 | case releaseDate 38 | } 39 | 40 | public init(parameterType: CardQueryParameterType, value: String) { 41 | super.init() 42 | self.name = parameterType.rawValue 43 | self.value = value 44 | } 45 | } 46 | 47 | public final class SetSearchParameter: SearchParameter { 48 | 49 | public enum SetQueryParameterType: String { 50 | case name 51 | case block 52 | } 53 | 54 | public init(parameterType: SetQueryParameterType, value: String) { 55 | super.init() 56 | self.name = parameterType.rawValue 57 | self.value = value 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /TestApplication/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TestApplication/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TestApplication/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /TestApplication/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /MTGSDKSwift/URLBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLBuilder.swift 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 4/5/18. 6 | // Copyright © 2018 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class URLBuilder { 12 | static func buildURLWithParameters(_ parameters: [SearchParameter], 13 | andConfig config: MTGSearchConfiguration = MTGSearchConfiguration.defaultConfiguration) -> URL? { 14 | var urlComponents = URLComponents() 15 | urlComponents.scheme = Constants.scheme 16 | urlComponents.host = Constants.host 17 | urlComponents.path = { 18 | if parameters is [CardSearchParameter] { 19 | return Constants.cardsEndpoint 20 | } else { 21 | return Constants.setsEndpoint 22 | } 23 | }() 24 | 25 | urlComponents.queryItems = buildQueryItemsFromParameters(parameters, config) 26 | 27 | debugPrint("MTGSDK URL: \(String(describing: urlComponents.url))\n") 28 | 29 | return urlComponents.url 30 | } 31 | 32 | private static func buildQueryItemsFromParameters(_ parameters: [SearchParameter], 33 | _ config: MTGSearchConfiguration = MTGSearchConfiguration.defaultConfiguration) -> [URLQueryItem] { 34 | var queryItems = [URLQueryItem]() 35 | 36 | let pageSizeQuery = URLQueryItem(name: "pageSize", value: String(config.pageSize)) 37 | let pageQuery = URLQueryItem(name: "page", value: String(config.pageTotal)) 38 | queryItems.append(pageQuery) 39 | queryItems.append(pageSizeQuery) 40 | 41 | for parameter in parameters { 42 | let name = parameter.name 43 | let value = parameter.value 44 | let item = URLQueryItem(name: name, value: value) 45 | queryItems.append(item) 46 | } 47 | 48 | return queryItems 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /MTGSDKSwift/Models/Card.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Card.swift 3 | // mtg-sdk-swift 4 | // 5 | // Created by Reed Carson on 2/24/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Card: Equatable, Decodable { 12 | public init() {} 13 | 14 | public var name: String? 15 | public var names: [String]? 16 | public var manaCost: String? 17 | public var cmc: Int? 18 | public var colors: [String]? 19 | public var colorIdentity: [String]? 20 | public var type: String? 21 | public var supertypes: [String]? 22 | public var types: [String]? 23 | public var subtypes: [String]? 24 | public var rarity: String? 25 | public var set: String? 26 | public var setName: String? 27 | public var text: String? 28 | public var artist: String? 29 | public var number: String? 30 | public var power: String? 31 | public var toughness: String? 32 | public var layout: String? 33 | public var multiverseid: String? 34 | public var imageUrl: String? 35 | public var rulings: [[String:String]]? 36 | public var foreignNames: [ForeignName]? 37 | public var printings: [String]? 38 | public var originalText: String? 39 | public var originalType: String? 40 | public var id: String? 41 | public var flavor: String? 42 | public var loyalty: String? 43 | public var gameFormat: String? 44 | public var releaseDate: String? 45 | public var legalities: [Legality]? 46 | 47 | public static func ==(lhs: Card, rhs: Card) -> Bool { 48 | return lhs.id == rhs.id 49 | } 50 | } 51 | 52 | public struct ForeignName: Decodable { 53 | public var name: String 54 | public var language: String 55 | public var multiverseid: Int? 56 | } 57 | 58 | public struct Legality: Decodable { 59 | public var format: String 60 | public var legality: String 61 | } 62 | 63 | public struct CardsResponse: ResponseObject, Decodable { 64 | public var cards: [Card] 65 | } 66 | -------------------------------------------------------------------------------- /MTGSDKSwift.xcodeproj/xcshareddata/xcschemes/MTGSDKSwiftTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 37 | 38 | 44 | 45 | 47 | 48 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /MTGSDKSwift.xcodeproj/xcshareddata/xcschemes/MTGSDKSwift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 63 | 69 | 70 | 71 | 72 | 78 | 79 | 85 | 86 | 87 | 88 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /MTGSDKSwiftTests/MTGSDKSwiftTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MTGSDKSwiftTests.swift 3 | // MTGSDKSwiftTests 4 | // 5 | // Created by Reed Carson on 2/27/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | 9 | import MTGSDKSwift 10 | import XCTest 11 | 12 | class MTGSDKSwiftTests: XCTestCase { 13 | 14 | var magic: Magic = Magic() 15 | 16 | override func setUp() { 17 | super.setUp() 18 | } 19 | } 20 | 21 | // MARK: - Card Search Tests 22 | 23 | extension MTGSDKSwiftTests { 24 | 25 | func testCardSearchNoResults() { 26 | let param = CardSearchParameter(parameterType: .name, value: "abcdefghijk") 27 | let exp = expectation(description: "fetchCards") 28 | 29 | magic.fetchCards([param]) { (result) in 30 | defer { 31 | exp.fulfill() 32 | } 33 | 34 | switch result { 35 | case .success(let cards): 36 | XCTAssertTrue(cards.count == 0) 37 | case .error(let error): 38 | XCTFail("Error fetching cards: \(error.localizedDescription)") 39 | } 40 | } 41 | waitForExpectations(timeout: 10, handler: nil) 42 | } 43 | 44 | func testCardSearchWithCards() { 45 | let param = CardSearchParameter(parameterType: .name, value: "lotus") 46 | let exp = expectation(description: "fetchCards") 47 | 48 | magic.fetchCards([param]) { (result) in 49 | defer { 50 | exp.fulfill() 51 | } 52 | 53 | switch result { 54 | case .success(let cards): 55 | XCTAssertTrue(cards.count > 0) 56 | case .error(let error): 57 | XCTFail("Error fetching cards: \(error.localizedDescription)") 58 | } 59 | } 60 | waitForExpectations(timeout: 10, handler: nil) 61 | } 62 | } 63 | 64 | // MARK: - Fetch Planeswalker 65 | 66 | extension MTGSDKSwiftTests { 67 | 68 | func testFetchKarnAndVerify() { 69 | let param = CardSearchParameter(parameterType: .name, value: "Karn Liberated") 70 | 71 | let exp = expectation(description: "fetchCards") 72 | 73 | magic.fetchCards([param]) { (result) in 74 | defer { 75 | exp.fulfill() 76 | } 77 | 78 | switch result { 79 | case .success(let cards): 80 | guard let card = cards.first(where: {$0.id == "fc5dff7e-489f-5a42-bf3f-926985aaef4a" }) else { 81 | XCTFail("unable to fetch expected test card") 82 | return 83 | } 84 | XCTAssertEqual("Karn Liberated", card.name) 85 | XCTAssertEqual("6", cards.first?.loyalty) 86 | XCTAssertEqual("{7}", card.manaCost) 87 | XCTAssertEqual(7, card.cmc) 88 | XCTAssertEqual(nil, card.colors) 89 | XCTAssertEqual(nil, card.colorIdentity) 90 | XCTAssertEqual("Legendary Planeswalker — Karn", card.type) 91 | XCTAssertEqual(["Legendary"], card.supertypes) 92 | case .error(let error): 93 | XCTFail("Error fetching cards: \(error.localizedDescription)") 94 | } 95 | } 96 | waitForExpectations(timeout: 10, handler: nil) 97 | } 98 | } 99 | 100 | // MARK: - Fetch Image Tests 101 | 102 | extension MTGSDKSwiftTests { 103 | func testFetchValidImage() { 104 | var card = Card() 105 | card.imageUrl = "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=391870&type=card" 106 | 107 | let exp = expectation(description: "fetchImageForCard") 108 | 109 | magic.fetchImageForCard(card) { (result) in 110 | defer { 111 | exp.fulfill() 112 | } 113 | 114 | switch result { 115 | case .success: 116 | break 117 | case .error(let error): 118 | XCTFail("Error getting image: \(error.localizedDescription)") 119 | } 120 | } 121 | 122 | waitForExpectations(timeout: 10, handler: nil) 123 | } 124 | 125 | func testFetchImageError() { 126 | let card = Card() 127 | let exp = expectation(description: "fetchImageForCard") 128 | 129 | magic.fetchImageForCard(card) { (result) in 130 | defer { 131 | exp.fulfill() 132 | } 133 | 134 | switch result { 135 | case .success: 136 | XCTFail("Got an image back for a card without an image") 137 | case .error: 138 | break 139 | } 140 | } 141 | 142 | waitForExpectations(timeout: 10, handler: nil) 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /MTGSDKSwift/MTGAPIService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MTGAPIService.swift 3 | // mtg-sdk-swift 4 | // 5 | // Created by Reed Carson on 2/24/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias JSONResults = [String:Any] 12 | typealias JSONDataCompletion = (Result<(data: Data, json: JSONResults)>) -> Void 13 | 14 | public enum Result { 15 | case success(T) 16 | case error(NetworkError) 17 | } 18 | 19 | protocol ResponseObject: Decodable {} 20 | 21 | final class MTGAPIService { 22 | 23 | /// Performs A query against the MTG APIs and calls back to the provided completion handler 24 | /// with a success or failure. 25 | /// 26 | /// - Parameters: 27 | /// - url: The MTG URL to hit. 28 | /// - completion: The completion handler block to handle the response. 29 | func mtgAPIQuery(url: URL, responseObject: T.Type, completion: @escaping (Result) -> Void) { 30 | let networkOperation = NetworkOperation(url: url) 31 | networkOperation.performOperation { 32 | result in 33 | switch result { 34 | case .success(let json): 35 | do { 36 | let result = try JSONDecoder().decode(T.self, from: json.data) 37 | completion(Result.success(result)) 38 | } catch { 39 | completion(Result.error(NetworkError.decodableError(error))) 40 | } 41 | case .error(let error): 42 | completion(Result.error(error)) 43 | } 44 | } 45 | } 46 | 47 | @available(iOS 15.0, *) 48 | func mtgAPIQuery(url: URL, responseObject: T.Type) async throws -> T { 49 | let networkOperation = NetworkOperation(url: url) 50 | 51 | let responseData = try await networkOperation.performOperation() 52 | 53 | do { 54 | return try JSONDecoder().decode(T.self, from: responseData) 55 | } catch { 56 | throw NetworkError.decodableError(error) 57 | } 58 | } 59 | 60 | func jsonQuery(url: URL, completion: @escaping (Result) -> Void) { 61 | let networkOperation = NetworkOperation(url: url) 62 | networkOperation.performOperation { 63 | result in 64 | switch result { 65 | case .success(let json): 66 | completion(Result.success(json.json)) 67 | case .error(let error): 68 | completion(Result.error(error)) 69 | } 70 | } 71 | } 72 | } 73 | 74 | final private class NetworkOperation { 75 | let url: URL 76 | 77 | init(url: URL) { 78 | self.url = url 79 | } 80 | 81 | func performOperation(completion: @escaping JSONDataCompletion) { 82 | URLSession.shared.dataTask(with: URLRequest(url: url)) { (data, response, error) in 83 | if let error = error { 84 | return completion(Result.error(NetworkError.requestError(error))) 85 | } 86 | 87 | guard let data = data else { 88 | return completion(Result.error(NetworkError.miscError("Network operation - No data returned"))) 89 | } 90 | 91 | if let httpResponse = (response as? HTTPURLResponse) { 92 | debugPrint("MTGSDK HTTPResponse - status code: \(httpResponse.statusCode)") 93 | 94 | switch httpResponse.statusCode { 95 | case 200..<300: 96 | break 97 | default: 98 | return completion(Result.error(NetworkError.unexpectedHTTPResponse(httpResponse))) 99 | } 100 | } 101 | 102 | do { 103 | let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) 104 | guard let json = jsonResponse as? JSONResults else { 105 | return completion(Result.error(NetworkError.miscError("Network operation - invalid json response"))) 106 | } 107 | completion(Result.success((data, json))) 108 | } catch { 109 | completion(Result.error(NetworkError.miscError("json serialization error"))) 110 | } 111 | }.resume() 112 | } 113 | 114 | @available(iOS 15.0, *) 115 | func performOperation() async throws -> Data { 116 | let (data, response) = try await URLSession.shared.data(for: URLRequest(url: url)) 117 | 118 | guard data.count > 0 else { 119 | throw NetworkError.miscError("Network operation - No data returned") 120 | } 121 | 122 | if let httpResponse = (response as? HTTPURLResponse) { 123 | debugPrint("MTGSDK HTTPResponse - status code: \(httpResponse.statusCode)") 124 | switch httpResponse.statusCode { 125 | case 200..<300: 126 | break 127 | default: 128 | throw NetworkError.unexpectedHTTPResponse(httpResponse) 129 | } 130 | } 131 | 132 | return data 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /MTGSDKSwiftTests/Resources/karn.json: -------------------------------------------------------------------------------- 1 | { 2 | "cards": [ 3 | { 4 | "name": "Karn Liberated", 5 | "manaCost": "{7}", 6 | "cmc": 7, 7 | "type": "Legendary Planeswalker — Karn", 8 | "supertypes": [ 9 | "Legendary" 10 | ], 11 | "types": [ 12 | "Planeswalker" 13 | ], 14 | "subtypes": [ 15 | "Karn" 16 | ], 17 | "rarity": "Mythic Rare", 18 | "set": "MM2", 19 | "setName": "Modern Masters 2015 Edition", 20 | "text": "+4: Target player exiles a card from their hand.\n−3: Exile target permanent.\n−14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated. Then put those cards onto the battlefield under your control.", 21 | "artist": "Jason Chan", 22 | "number": "4", 23 | "layout": "normal", 24 | "multiverseid": 397828, 25 | "imageUrl": "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=397828&type=card", 26 | "loyalty": 6, 27 | "rulings": [ 28 | { 29 | "date": "2011-06-01", 30 | "text": "Karn's first and third abilities are linked. Similarly, Karn's second and third abilities are linked. Only cards exiled by either of Karn's first two abilities will remain in exile when the game restarts." 31 | }, 32 | { 33 | "date": "2011-06-01", 34 | "text": "A game that restarts immediately ends. The players in that game then immediately begin a new game. No player wins, loses, or draws the original game as a result of Karn's ability." 35 | }, 36 | { 37 | "date": "2011-06-01", 38 | "text": "In a multiplayer games (a game that started with three or more players in it), any player that left the game before it was restarted with Karn's ability won't be involved in the new game." 39 | }, 40 | { 41 | "date": "2011-06-01", 42 | "text": "The player who controlled the ability that restarted the game is the starting player in the new game. The new game starts like a game normally does: -- Each player shuffles their deck (except the cards left in exile by Karn's ability). -- Each player's life total becomes 20 (or the starting life total for whatever format you're playing). -- Players draw a hand of seven cards. Players may take mulligans. -- Players may take actions based on cards in their opening hands, such as Chancellors and Leylines." 43 | }, 44 | { 45 | "date": "2011-06-01", 46 | "text": "After the pre-game procedure is complete, but before the new game's first turn, Karn's ability finishes resolving and the cards left in exile are put onto the battlefield. If this causes any triggered abilities to trigger, those abilities are put onto the stack at the beginning of the first upkeep step." 47 | }, 48 | { 49 | "date": "2011-06-01", 50 | "text": "Creatures put onto the battlefield due to Karn's ability will have been under their controller's control continuously since the beginning of the first turn. They can attack and their activated abilities with {T} in the cost can be activated." 51 | }, 52 | { 53 | "date": "2011-06-01", 54 | "text": "Any permanents put onto the battlefield with Karn's ability that entered the battlefield tapped will untap during their controller's first untap step." 55 | }, 56 | { 57 | "date": "2011-06-01", 58 | "text": "No actions taken in the game that was restarted apply to the new game. For example, if you were dealt damage by Stigma Lasher in the original game, the effect that states you can't gain life doesn't carry over to the new game." 59 | }, 60 | { 61 | "date": "2011-06-01", 62 | "text": "Players won't have any poison counters or emblems they had in the original game." 63 | }, 64 | { 65 | "date": "2011-06-01", 66 | "text": "In a Commander game, players put their commanders into the command zone before shuffling their deck." 67 | }, 68 | { 69 | "date": "2011-06-01", 70 | "text": "The number of times a player has cast their commander from the command zone resets to zero. Also, the amount of combat damage dealt to players by each commander is reset to 0." 71 | }, 72 | { 73 | "date": "2011-06-01", 74 | "text": "If a player's commander was exiled with Karn at the game restarted, that commander won't be put into the command zone at the beginning of the game. It will be put onto the battlefield when Karn's ability finishes resolving." 75 | }, 76 | { 77 | "date": "2011-06-01", 78 | "text": "In a multiplayer game using the limited range of influence option, all players are affected and will restart the game, not just those within the range of influence of the ability's controller." 79 | } 80 | ], 81 | "foreignNames": [ 82 | { 83 | "name": "重获自由的卡恩", 84 | "imageUrl": "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=398077&type=card", 85 | "language": "Chinese Simplified", 86 | "multiverseid": 398077 87 | }, 88 | { 89 | "name": "解放された者、カーン", 90 | "imageUrl": "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=398326&type=card", 91 | "language": "Japanese", 92 | "multiverseid": 398326 93 | } 94 | ], 95 | "printings": [ 96 | "NPH", 97 | "MM2" 98 | ], 99 | "originalText": "+4: Target player exiles a card from his or her hand.\n−3: Exile target permanent.\n−14: Restart the game, leaving in exile all non-Aura permanent cards exiled with Karn Liberated. Then put those cards onto the battlefield under your control.", 100 | "originalType": "Planeswalker — Karn", 101 | "legalities": [ 102 | { 103 | "format": "Commander", 104 | "legality": "Legal" 105 | }, 106 | { 107 | "format": "Legacy", 108 | "legality": "Legal" 109 | }, 110 | { 111 | "format": "Modern", 112 | "legality": "Legal" 113 | }, 114 | { 115 | "format": "Vintage", 116 | "legality": "Legal" 117 | } 118 | ], 119 | "id": "6dbb000f1dffa20fbb9159b7ac36b814d209558c" 120 | } 121 | ] 122 | } 123 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.3) 5 | addressable (2.8.0) 6 | public_suffix (>= 2.0.2, < 5.0) 7 | artifactory (3.0.15) 8 | atomos (0.1.3) 9 | aws-eventstream (1.1.1) 10 | aws-partitions (1.472.0) 11 | aws-sdk-core (3.115.0) 12 | aws-eventstream (~> 1, >= 1.0.2) 13 | aws-partitions (~> 1, >= 1.239.0) 14 | aws-sigv4 (~> 1.1) 15 | jmespath (~> 1.0) 16 | aws-sdk-kms (1.44.0) 17 | aws-sdk-core (~> 3, >= 3.112.0) 18 | aws-sigv4 (~> 1.1) 19 | aws-sdk-s3 (1.96.1) 20 | aws-sdk-core (~> 3, >= 3.112.0) 21 | aws-sdk-kms (~> 1) 22 | aws-sigv4 (~> 1.1) 23 | aws-sigv4 (1.2.3) 24 | aws-eventstream (~> 1, >= 1.0.2) 25 | babosa (1.0.4) 26 | claide (1.0.3) 27 | colored (1.2) 28 | colored2 (3.1.2) 29 | commander (4.6.0) 30 | highline (~> 2.0.0) 31 | declarative (0.0.20) 32 | digest-crc (0.6.3) 33 | rake (>= 12.0.0, < 14.0.0) 34 | domain_name (0.5.20190701) 35 | unf (>= 0.0.5, < 1.0.0) 36 | dotenv (2.7.6) 37 | emoji_regex (3.2.2) 38 | excon (0.83.0) 39 | faraday (1.4.3) 40 | faraday-em_http (~> 1.0) 41 | faraday-em_synchrony (~> 1.0) 42 | faraday-excon (~> 1.1) 43 | faraday-net_http (~> 1.0) 44 | faraday-net_http_persistent (~> 1.1) 45 | multipart-post (>= 1.2, < 3) 46 | ruby2_keywords (>= 0.0.4) 47 | faraday-cookie_jar (0.0.7) 48 | faraday (>= 0.8.0) 49 | http-cookie (~> 1.0.0) 50 | faraday-em_http (1.0.0) 51 | faraday-em_synchrony (1.0.0) 52 | faraday-excon (1.1.0) 53 | faraday-net_http (1.0.1) 54 | faraday-net_http_persistent (1.1.0) 55 | faraday_middleware (1.0.0) 56 | faraday (~> 1.0) 57 | fastimage (2.2.4) 58 | fastlane (2.187.0) 59 | CFPropertyList (>= 2.3, < 4.0.0) 60 | addressable (>= 2.3, < 3.0.0) 61 | artifactory (~> 3.0) 62 | aws-sdk-s3 (~> 1.0) 63 | babosa (>= 1.0.3, < 2.0.0) 64 | bundler (>= 1.12.0, < 3.0.0) 65 | colored 66 | commander (~> 4.6) 67 | dotenv (>= 2.1.1, < 3.0.0) 68 | emoji_regex (>= 0.1, < 4.0) 69 | excon (>= 0.71.0, < 1.0.0) 70 | faraday (~> 1.0) 71 | faraday-cookie_jar (~> 0.0.6) 72 | faraday_middleware (~> 1.0) 73 | fastimage (>= 2.1.0, < 3.0.0) 74 | gh_inspector (>= 1.1.2, < 2.0.0) 75 | google-apis-androidpublisher_v3 (~> 0.1) 76 | google-apis-playcustomapp_v1 (~> 0.1) 77 | google-cloud-storage (~> 1.31) 78 | highline (~> 2.0) 79 | json (< 3.0.0) 80 | jwt (>= 2.1.0, < 3) 81 | mini_magick (>= 4.9.4, < 5.0.0) 82 | multipart-post (~> 2.0.0) 83 | naturally (~> 2.2) 84 | plist (>= 3.1.0, < 4.0.0) 85 | rubyzip (>= 2.0.0, < 3.0.0) 86 | security (= 0.1.3) 87 | simctl (~> 1.6.3) 88 | terminal-notifier (>= 2.0.0, < 3.0.0) 89 | terminal-table (>= 1.4.5, < 2.0.0) 90 | tty-screen (>= 0.6.3, < 1.0.0) 91 | tty-spinner (>= 0.8.0, < 1.0.0) 92 | word_wrap (~> 1.0.0) 93 | xcodeproj (>= 1.13.0, < 2.0.0) 94 | xcpretty (~> 0.3.0) 95 | xcpretty-travis-formatter (>= 0.0.3) 96 | gh_inspector (1.1.3) 97 | google-apis-androidpublisher_v3 (0.7.0) 98 | google-apis-core (>= 0.3, < 2.a) 99 | google-apis-core (0.4.0) 100 | addressable (~> 2.5, >= 2.5.1) 101 | googleauth (>= 0.16.2, < 2.a) 102 | httpclient (>= 2.8.1, < 3.a) 103 | mini_mime (~> 1.0) 104 | representable (~> 3.0) 105 | retriable (>= 2.0, < 4.a) 106 | rexml 107 | webrick 108 | google-apis-iamcredentials_v1 (0.5.0) 109 | google-apis-core (>= 0.3, < 2.a) 110 | google-apis-playcustomapp_v1 (0.4.0) 111 | google-apis-core (>= 0.3, < 2.a) 112 | google-apis-storage_v1 (0.5.0) 113 | google-apis-core (>= 0.3, < 2.a) 114 | google-cloud-core (1.6.0) 115 | google-cloud-env (~> 1.0) 116 | google-cloud-errors (~> 1.0) 117 | google-cloud-env (1.5.0) 118 | faraday (>= 0.17.3, < 2.0) 119 | google-cloud-errors (1.1.0) 120 | google-cloud-storage (1.32.0) 121 | addressable (~> 2.5) 122 | digest-crc (~> 0.4) 123 | google-apis-iamcredentials_v1 (~> 0.1) 124 | google-apis-storage_v1 (~> 0.1) 125 | google-cloud-core (~> 1.6) 126 | googleauth (>= 0.16.2, < 2.a) 127 | mini_mime (~> 1.0) 128 | googleauth (0.16.2) 129 | faraday (>= 0.17.3, < 2.0) 130 | jwt (>= 1.4, < 3.0) 131 | memoist (~> 0.16) 132 | multi_json (~> 1.11) 133 | os (>= 0.9, < 2.0) 134 | signet (~> 0.14) 135 | highline (2.0.3) 136 | http-cookie (1.0.4) 137 | domain_name (~> 0.5) 138 | httpclient (2.8.3) 139 | jmespath (1.4.0) 140 | json (2.5.1) 141 | jwt (2.2.3) 142 | memoist (0.16.2) 143 | mini_magick (4.11.0) 144 | mini_mime (1.1.0) 145 | multi_json (1.15.0) 146 | multipart-post (2.0.0) 147 | nanaimo (0.3.0) 148 | naturally (2.2.1) 149 | os (1.1.1) 150 | plist (3.6.0) 151 | public_suffix (4.0.6) 152 | rake (13.0.3) 153 | representable (3.1.1) 154 | declarative (< 0.1.0) 155 | trailblazer-option (>= 0.1.1, < 0.2.0) 156 | uber (< 0.2.0) 157 | retriable (3.1.2) 158 | rexml (3.2.5) 159 | rouge (2.0.7) 160 | ruby2_keywords (0.0.4) 161 | rubyzip (2.3.0) 162 | security (0.1.3) 163 | signet (0.15.0) 164 | addressable (~> 2.3) 165 | faraday (>= 0.17.3, < 2.0) 166 | jwt (>= 1.5, < 3.0) 167 | multi_json (~> 1.10) 168 | simctl (1.6.8) 169 | CFPropertyList 170 | naturally 171 | terminal-notifier (2.0.0) 172 | terminal-table (1.8.0) 173 | unicode-display_width (~> 1.1, >= 1.1.1) 174 | trailblazer-option (0.1.1) 175 | tty-cursor (0.7.1) 176 | tty-screen (0.8.1) 177 | tty-spinner (0.9.3) 178 | tty-cursor (~> 0.7) 179 | uber (0.1.0) 180 | unf (0.1.4) 181 | unf_ext 182 | unf_ext (0.0.7.7) 183 | unicode-display_width (1.7.0) 184 | webrick (1.7.0) 185 | word_wrap (1.0.0) 186 | xcodeproj (1.19.0) 187 | CFPropertyList (>= 2.3.3, < 4.0) 188 | atomos (~> 0.1.3) 189 | claide (>= 1.0.2, < 2.0) 190 | colored2 (~> 3.1) 191 | nanaimo (~> 0.3.0) 192 | xcpretty (0.3.0) 193 | rouge (~> 2.0.7) 194 | xcpretty-travis-formatter (1.0.1) 195 | xcpretty (~> 0.2, >= 0.0.7) 196 | 197 | PLATFORMS 198 | x86_64-darwin-20 199 | x86_64-linux 200 | 201 | DEPENDENCIES 202 | fastlane 203 | 204 | BUNDLED WITH 205 | 2.2.21 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## MTGSDKSwift 2 | #### Magic: The Gathering SDK - Swift 3 | ##### A lightweight framework that makes interacting with the magicthegathering.io api quick, easy and safe. 4 | 5 | 6 | 7 | 8 | 9 | 10 | #### Installation 11 | 12 | ##### Install with SPM 13 | 14 | ##### Install with Cocoapods 15 | - add `pod 'MTGSDKSwift'` to your podfile 16 | - run pod install 17 | 18 | ##### Install with Carthage 19 | 20 | * copy the Cartfile above into your project folder 21 | * in terminal, navigate to your project folder and run the command 'carthage update' 22 | * drag the .framework file into your project in xcode. It will be in the newly created Carthage/Build/iOS folder in your project directory 23 | * drag the framework to the Linked Frameworks And Libraries slot and Embedded Frameworks slot 24 | 25 | You can also just download this project and drag the framework file into your project instead of messing with Carthage. 26 | 27 | 28 | #### Use 29 | 30 | ````swift 31 | import MTGSDKSwift 32 | 33 | let magic = Magic() 34 | ```` 35 | You can 36 | 37 | ````swift 38 | fetchCards(_:completion:) 39 | fetchSets(_:completion:) 40 | fetchJSON(_:completion:) 41 | fetchImageForCard(_:completion:) 42 | generateBoosterForSet(_:completion:) 43 | ```` 44 | ##### First: Configure your search parameters 45 | Parameters can be constructed as follows: 46 | 47 | ````swift 48 | let color = CardSearchParameter(parameterType: .colors, value: "black") 49 | let cmc = CardSearchParameter(parameterType: .cmc, value: "2") 50 | let setCode = CardSearchParameter(parameterType: .set, value: "AER") 51 | ```` 52 | 53 | Search parameters come in two flavors: Card and SetSearchParameter. Each one contains an enum holding the valid query names for either cards or sets searches. 54 | 55 | Desired search parameters are grouped into an array and passed to the fetch method. 56 | 57 | ````swift 58 | magic.fetchCards(withParameters: [color,cmc,setCode]) { 59 | cards, error in 60 | 61 | if let error = error { 62 | //handle your error 63 | } 64 | 65 | for c in cards! { 66 | print(c.name) 67 | } 68 | 69 | } 70 | ```` 71 | 72 | 73 | The completion contains an optional array of the appropriate type and an optional error type enum, NetworkError. Details for this enum are further down. 74 | 75 | The default number of results that will be retreived is 12. This can be set to 100, and for more results the number of pages must be increased. Page number and page size can be set by calling 76 | 77 | ````swift 78 | magic.pageTotal = "1" 79 | //and 80 | magic.pageSize = "9000" 81 | ```` 82 | Additionally, some helpful console messages such as the URL string that is being sent to the server, how many cards or sets were retreived, and a message indicating that the network query has begun can be enabled by calling a static method on Magic. 83 | 84 | ````swift 85 | Magic.enableLogging = true 86 | ```` 87 | ##### Fetching unparsed json 88 | fetchJSON(_:completion:) can be used to get the unparsed json in case you want to do something specific with it. 89 | 90 | ##### Fetching The Card Image 91 | 92 | fetchImageForCard works similarly to fetchCards, and will retreive the card image of the card you pass to it, if one is available. Some promo and special cards do not contain imageURL data. NetworkError will communicate this if true. Notably, cards in sets whose set code is prepended with "p" (pMEI, pGMD etc) may be missing this data. Most promotional cards will be missing image data as well. 93 | 94 | __Important note on image fetching:__ the card imageUrl refers to an HTTP address (gathere.wizards.com), which are as of ios9 by default blocked by App Transport Security. In order for image fetch to succede you must paste the following entry into your plist. This can also be added through the ios Target Properties menu but this is just quicker. [StackOverflow has a more detailed description of this issue.](http://stackoverflow.com/questions/31254725/transport-security-has-blocked-a-cleartext-http) 95 | 96 | ````xml 97 | NSAppTransportSecurity 98 | 99 | NSExceptionDomains 100 | 101 | wizards.com 102 | 103 | NSIncludesSubdomains 104 | 105 | NSTemporaryExceptionAllowsInsecureHTTPLoads 106 | 107 | NSTemporaryExceptionMinimumTLSVersion 108 | TLSv1.1 109 | 110 | 111 | 112 | ```` 113 | 114 | ##### Simulating a Booster 115 | 116 | generateBoosterForSet(_:completion:) will return an array of [Card] which simulates what one might find opening a physical booster. 117 | 118 | 119 | #### class - Card 120 | ````swift 121 | public var name: String? 122 | public var names: [String]? 123 | public var manaCost: String? 124 | public var cmc: Int? 125 | public var colors: [String]? 126 | public var colorIdentity: [String]? 127 | public var type: String? 128 | public var supertypes: [String]? 129 | public var types: [String]? 130 | public var subtypes: [String]? 131 | public var rarity: String? 132 | public var set: String? 133 | public var text: String? 134 | public var artist: String? 135 | public var number: String? 136 | public var power: String? 137 | public var toughness: String? 138 | public var layout: String? 139 | public var multiverseid: Int? 140 | public var imageURL: String? 141 | public var rulings: [[String:String]]? 142 | public var foreignNames: [[String:String]]? 143 | public var printings: [String]? 144 | public var originalText: String? 145 | public var originalType: String? 146 | public var id: String? 147 | public var flavor: String? 148 | 149 | public static func ==(lhs: Card, rhs: Card) -> Bool { 150 | return lhs.id == rhs.id 151 | } 152 | ```` 153 | Not all properties will exist for all mtg cards. 154 | 155 | The ID property is a unique identifier given to all cards and is useful for conforming Card to Equatable for example. Card names are not reliable for use as identifiers: There will be multiple "Serra Angel"s for example, one for each printing, but each one will have a unique ID. 156 | 157 | The following static function is provided for convienence in order to filter duplicate cards out of an array of [Card], if you have results containing the same card in multiple printings. 158 | 159 | ````swift 160 | FilterResults.removeDuplicateCardsByName(_:) -> [Card] 161 | ```` 162 | 163 | #### class CardSet 164 | ````swift 165 | public var code: String? 166 | public var name: String? 167 | public var block: String? 168 | public var type: String? 169 | public var border: String? 170 | public var releaseDate: String? 171 | public var magicCardsInfoCode: String? 172 | public var booster: [[String]]? 173 | ```` 174 | #### class CardSearchParameter, available parameters 175 | 176 | ````swift 177 | case name 178 | case cmc 179 | case colors 180 | case type 181 | case supertypes 182 | case subtypes 183 | case rarity 184 | case text 185 | case set 186 | case artist 187 | case power 188 | case toughness 189 | case multiverseid 190 | case gameFormat 191 | ```` 192 | 193 | * colors 194 | * "red,black,white" in quotes will return exact match 195 | * red,black,white will include multicolors 196 | * red|black|white will not return multicolors 197 | * red,black|white will return multicolor red and black, or red and white cards 198 | 199 | see the official API documentation for more information about expected inputs and return - 200 | [magicthegathering.io docs](http://docs.magicthegathering.io/#overview) 201 | 202 | #### class SetSearchParameter, vailable parameters 203 | ````swift 204 | case name 205 | case block 206 | ```` 207 | 208 | #### enum NetworkError 209 | 210 | ````swift 211 | public enum NetworkError: Error { 212 | case requestError(Error) 213 | case unexpectedHTTPResponse(HTTPURLResponse) 214 | case fetchCardImageError(String) 215 | case miscError(String) 216 | } 217 | ```` 218 | * case requestError(Error) 219 | * will contain the error generated by the dataTask completion if it exists 220 | * case unexpectedHTTPResponse(HTTPURLResponse) 221 | * will contain the HTTPresponse generated by dataTask completion if anything other than success 200..<300 is generated 222 | * case fetchCardImageError(String) 223 | * associated value will contain information about a failed image fetch 224 | * case miscError(String) 225 | * associated value will contain information about errors such as constructing URL failures 226 | 227 | #### Typealiases 228 | ````swift 229 | public typealias JSONResults = [String:Any] 230 | public typealias JSONCompletionWithError = (JSONResults?, NetworkError?) -> Void 231 | public typealias CardImageCompletion = (UIImage?, NetworkError?) -> Void 232 | public typealias CardCompletion = ([Card]?, NetworkError?) -> Void 233 | public typealias SetCompletion = ([CardSet]?, NetworkError?) -> Void 234 | -------------------------------------------------------------------------------- /MTGSDKSwift/MagicalCardManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MagicalCardManager.swift 3 | // MTGSDKSwift 4 | // 5 | // Created by Reed Carson on 3/1/17. 6 | // Copyright © 2017 Reed Carson. All rights reserved. 7 | // 8 | #if canImport(AppKit) 9 | import AppKit 10 | #elseif canImport(UIKit) 11 | import UIKit 12 | #endif 13 | 14 | final public class Magic { 15 | public typealias CardCompletion = (Result<[Card]>) -> Void 16 | public typealias SetCompletion = (Result<[CardSet]>) -> Void 17 | 18 | /// Should the Magic API log messages to the `print` function? Defaults to true. 19 | public static var enableLogging = true 20 | 21 | private let mtgAPIService = MTGAPIService() 22 | 23 | /// Default initialization 24 | public init() { } 25 | 26 | /// Reteives an array of Cards which match the parameters given. 27 | /// See https://docs.magicthegathering.io/#api_v1cards_list for more info. 28 | /// 29 | /// - Parameters: 30 | /// - parameters: The Card Search Parameters that you'd like to search with. 31 | /// - configuration: The Search Configuration (defaults to `.defaultConfiguration`). 32 | /// - completion: The completion handler (for success / failure response). 33 | public func fetchCards(_ parameters: [CardSearchParameter], 34 | configuration: MTGSearchConfiguration = .defaultConfiguration, 35 | completion: @escaping CardCompletion) { 36 | 37 | guard let url = URLBuilder.buildURLWithParameters(parameters, andConfig: configuration) else { 38 | completion(Result.error(NetworkError.miscError("fetchCards url build failed"))) 39 | return 40 | } 41 | 42 | mtgAPIService.mtgAPIQuery(url: url, responseObject: CardsResponse.self) { 43 | result in 44 | switch result { 45 | case .success(let results): 46 | completion(Result.success(results.cards)) 47 | case .error(let error): 48 | completion(Result.error(error)) 49 | } 50 | } 51 | } 52 | 53 | /// Retrieves an array of Cards which match the parameters given using Swift concurrency and utilizes `async await`. 54 | /// See https://docs.magicthegathering.io/#api_v1cards_list for more info. 55 | /// 56 | /// - Parameters: 57 | /// - parameters: The Card Search Parameters that you'd like to search with. 58 | /// - configuration: The Search Configuration (defaults to `.defaultConfiguration`). 59 | @available(iOS 15.0, *) 60 | public func fetchCards(_ parameters: [CardSearchParameter], 61 | configuration: MTGSearchConfiguration = .defaultConfiguration) async throws -> [Card] { 62 | guard let url = URLBuilder.buildURLWithParameters(parameters, andConfig: configuration) else { 63 | throw NetworkError.miscError("fetchCards URL build failed") 64 | } 65 | 66 | return try await mtgAPIService.mtgAPIQuery(url: url, responseObject: CardsResponse.self).cards 67 | } 68 | 69 | /// Reteives an array of CardSet which matches the parameters given. 70 | /// See https://docs.magicthegathering.io/#api_v1sets_list for more info. 71 | /// 72 | /// - Parameters: 73 | /// - parameters: The Card Set search parameters you want to search for. 74 | /// - configuration: The Search Configuration, defaults to `.defaultConfiguration`. 75 | /// - completion: The completion handler (for success / failure response). 76 | public func fetchSets(_ parameters: [SetSearchParameter], 77 | configuration: MTGSearchConfiguration = .defaultConfiguration, 78 | completion: @escaping SetCompletion) { 79 | guard let url = URLBuilder.buildURLWithParameters(parameters, andConfig: configuration) else { 80 | return completion(Result.error(NetworkError.miscError("fetchSets url build failed"))) 81 | } 82 | 83 | mtgAPIService.mtgAPIQuery(url: url, responseObject: SetsResponse.self) { 84 | result in 85 | switch result { 86 | case .success(let setsResponse): 87 | completion(Result.success(setsResponse.sets)) 88 | case .error(let error): 89 | completion(Result.error(error)) 90 | } 91 | } 92 | } 93 | 94 | /// Fetch JSON returns the raw json data rather than an Array of Card or CardSet. It will return json 95 | /// for sets or cards depending on what you feed it. 96 | /// 97 | /// - Parameters: 98 | /// - parameters: either [CardSearchParameter] or [SetSearchParameter] 99 | /// - configuration: The Search Configuration, defaults to `.defaultConfiguration`. 100 | /// - completion: The completion handler (for success / failure response). 101 | public func fetchJSON(_ parameters: [SearchParameter], 102 | configuration: MTGSearchConfiguration = .defaultConfiguration, 103 | completion: @escaping (Result) -> Void) { 104 | 105 | guard let url = URLBuilder.buildURLWithParameters(parameters, andConfig: configuration) else { 106 | completion(Result.error(NetworkError.miscError("fetchJSON url build failed"))) 107 | return 108 | } 109 | 110 | mtgAPIService.jsonQuery(url: url) { 111 | result in 112 | switch result { 113 | case .success: 114 | completion(result) 115 | case .error(let error): 116 | completion(Result.error(NetworkError.requestError(error))) 117 | return 118 | } 119 | } 120 | } 121 | 122 | #if canImport(UIKit) 123 | public typealias CardImageCompletion = (Result) -> Void 124 | 125 | /// Retreives a UIImage based on the imageURL of the Card passed in 126 | /// 127 | /// - Parameters: 128 | /// - card: The card you wish to get the image for. 129 | /// - completion: The completion handler (for success / failure response). 130 | public func fetchImageForCard(_ card: Card, completion: @escaping CardImageCompletion) { 131 | guard let imgurl = card.imageUrl else { 132 | return completion(Result.error(NetworkError.fetchCardImageError("fetchImageForCard card imageURL was nil"))) 133 | } 134 | 135 | guard let url = URL(string: imgurl) else { 136 | return completion(Result.error(NetworkError.fetchCardImageError("fetchImageForCard url build failed"))) 137 | } 138 | 139 | do { 140 | let data = try Data(contentsOf: url) 141 | guard let img = UIImage(data: data) else { 142 | return completion(Result.error(NetworkError.fetchCardImageError("could not create uiimage from data"))) 143 | } 144 | completion(Result.success(img)) 145 | } catch { 146 | completion(Result.error(NetworkError.fetchCardImageError("data from contents of url failed"))) 147 | } 148 | } 149 | #endif 150 | 151 | #if canImport(AppKit) 152 | public typealias CardImageCompletion = (Result) -> Void 153 | 154 | /// Retreives a NSImage based on the imageURL of the Card passed in 155 | /// 156 | /// - Parameters: 157 | /// - card: The card you wish to get the image for. 158 | /// - completion: The completion handler (for success / failure response). 159 | public func fetchImageForCard(_ card: Card, completion: @escaping CardImageCompletion) { 160 | guard let imgurl = card.imageUrl else { 161 | return completion(Result.error(NetworkError.fetchCardImageError("fetchImageForCard card imageURL was nil"))) 162 | } 163 | 164 | guard let url = URL(string: imgurl) else { 165 | return completion(Result.error(NetworkError.fetchCardImageError("fetchImageForCard url build failed"))) 166 | } 167 | 168 | do { 169 | let data = try Data(contentsOf: url) 170 | guard let img = NSImage(data: data) else { 171 | return completion(Result.error(NetworkError.fetchCardImageError("could not create uiimage from data"))) 172 | } 173 | completion(Result.success(img)) 174 | } catch { 175 | completion(Result.error(NetworkError.fetchCardImageError("data from contents of url failed"))) 176 | } 177 | } 178 | #endif 179 | 180 | /// This function simulates opening a booster pack for the given set, producing an array of [Card] 181 | /// 182 | /// - Parameters: 183 | /// - setCode: the set code of the desired set 184 | /// - completion: The completion handler (for success / failure response). 185 | public func generateBoosterForSet(_ setCode: String, completion: @escaping CardCompletion) { 186 | let urlString = Constants.baseEndpoint + setCode + Constants.generateBoosterPath 187 | 188 | guard let url = URL(string: urlString) else { 189 | return completion(Result.error(NetworkError.miscError("generateBooster - build url fail"))) 190 | } 191 | 192 | mtgAPIService.mtgAPIQuery(url: url, responseObject: CardsResponse.self) { 193 | result in 194 | switch result { 195 | case .success(let results): 196 | completion(Result.success(results.cards)) 197 | case .error(let error): 198 | completion(Result.error(error)) 199 | } 200 | } 201 | } 202 | } 203 | 204 | final public class ResultsFilter { 205 | 206 | /** 207 | If an array of Card contains cards with identical names, likely due to multiple printings, this function leaves only one version of that card. You will only have one "Scathe Zombie" instead of 5 "Scathe Zombie", the only difference between them being the set they were printed in. 208 | 209 | - parameter cards: [Card] 210 | - returns: [Card] consisting of Cards without duplicate names 211 | */ 212 | 213 | static public func removeDuplicateCardsByName(_ cards: [Card]) -> [Card] { 214 | var uniqueNames = [String]() 215 | var uniqueCards = [Card]() 216 | 217 | for c in cards { 218 | if let name = c.name { 219 | if !uniqueNames.contains(name) { 220 | uniqueCards.append(c) 221 | } 222 | uniqueNames.append(name) 223 | } 224 | } 225 | 226 | return uniqueCards 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /MTGSDKSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5B18A9821E69EB0B0026E648 /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B18A9811E69EB0B0026E648 /* NetworkError.swift */; }; 11 | 5B6092D9215EA8E000CDD46A /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 5B6092D8215EA8DF00CDD46A /* Resources */; }; 12 | 5B6DC20C1E64A01A000DF60C /* CardSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6DC20B1E64A01A000DF60C /* CardSet.swift */; }; 13 | 5B6DC20E1E64A1A0000DF60C /* SearchParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6DC20D1E64A1A0000DF60C /* SearchParameter.swift */; }; 14 | 5B71E73A282BED55006C7D1F /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 5B71E739282BED55006C7D1F /* README.md */; }; 15 | 5B87D68720596D6B0098553C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B87D68620596D6B0098553C /* AppDelegate.swift */; }; 16 | 5B87D68920596D6B0098553C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B87D68820596D6B0098553C /* ViewController.swift */; }; 17 | 5B87D68C20596D6B0098553C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B87D68A20596D6B0098553C /* Main.storyboard */; }; 18 | 5B87D68E20596D6B0098553C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5B87D68D20596D6B0098553C /* Assets.xcassets */; }; 19 | 5B87D69120596D6B0098553C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5B87D68F20596D6B0098553C /* LaunchScreen.storyboard */; }; 20 | 5BB0E88B205FF9AA00FE67F6 /* MTGSDKSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD04DA91E64943C00E5ED27 /* MTGSDKSwift.framework */; }; 21 | 5BB0E88C205FF9AA00FE67F6 /* MTGSDKSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD04DA91E64943C00E5ED27 /* MTGSDKSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | 5BC6D7EE1E67B7A00090650A /* MagicalCardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC6D7ED1E67B7A00090650A /* MagicalCardManager.swift */; }; 23 | 5BD04DB31E64943C00E5ED27 /* MTGSDKSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD04DA91E64943C00E5ED27 /* MTGSDKSwift.framework */; }; 24 | 5BD04DB81E64943C00E5ED27 /* MTGSDKSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD04DB71E64943C00E5ED27 /* MTGSDKSwiftTests.swift */; }; 25 | 5BD04DBA1E64943C00E5ED27 /* MTGSDKSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD04DAC1E64943C00E5ED27 /* MTGSDKSwift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 26 | 5BD04DC51E64945800E5ED27 /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD04DC31E64945800E5ED27 /* Card.swift */; }; 27 | 5BD04DC61E64945800E5ED27 /* MTGAPIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD04DC41E64945800E5ED27 /* MTGAPIService.swift */; }; 28 | 5BDF34C820854F1B007265DF /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF34C720854F1B007265DF /* Constants.swift */; }; 29 | 5BDF34CB2085500E007265DF /* MTGSearchConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF34CA2085500E007265DF /* MTGSearchConfiguration.swift */; }; 30 | 5BE24D202076D14A00EB0573 /* URLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BE24D1F2076D14A00EB0573 /* URLBuilder.swift */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 5BB0E88D205FF9AA00FE67F6 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 5BD04DA01E64943C00E5ED27 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 5BD04DA81E64943C00E5ED27; 39 | remoteInfo = MTGSDKSwift; 40 | }; 41 | 5BD04DB41E64943C00E5ED27 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = 5BD04DA01E64943C00E5ED27 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = 5BD04DA81E64943C00E5ED27; 46 | remoteInfo = MTGSDKSwift; 47 | }; 48 | /* End PBXContainerItemProxy section */ 49 | 50 | /* Begin PBXCopyFilesBuildPhase section */ 51 | 5BB0E88F205FF9AA00FE67F6 /* Embed Frameworks */ = { 52 | isa = PBXCopyFilesBuildPhase; 53 | buildActionMask = 2147483647; 54 | dstPath = ""; 55 | dstSubfolderSpec = 10; 56 | files = ( 57 | 5BB0E88C205FF9AA00FE67F6 /* MTGSDKSwift.framework in Embed Frameworks */, 58 | ); 59 | name = "Embed Frameworks"; 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXCopyFilesBuildPhase section */ 63 | 64 | /* Begin PBXFileReference section */ 65 | 5B18A9811E69EB0B0026E648 /* NetworkError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = ""; }; 66 | 5B6092D8215EA8DF00CDD46A /* Resources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Resources; sourceTree = ""; }; 67 | 5B6DC20B1E64A01A000DF60C /* CardSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardSet.swift; sourceTree = ""; }; 68 | 5B6DC20D1E64A1A0000DF60C /* SearchParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchParameter.swift; sourceTree = ""; }; 69 | 5B71E739282BED55006C7D1F /* README.md */ = {isa = PBXFileReference; explicitFileType = net.daringfireball.markdown; fileEncoding = 4; path = README.md; sourceTree = ""; }; 70 | 5B71E73B282BEFFD006C7D1F /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 71 | 5B87D68420596D6B0098553C /* TestApplication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApplication.app; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | 5B87D68620596D6B0098553C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 73 | 5B87D68820596D6B0098553C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 74 | 5B87D68B20596D6B0098553C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 75 | 5B87D68D20596D6B0098553C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 76 | 5B87D69020596D6B0098553C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 77 | 5B87D69220596D6B0098553C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 78 | 5BC6D7ED1E67B7A00090650A /* MagicalCardManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MagicalCardManager.swift; sourceTree = ""; }; 79 | 5BD04DA91E64943C00E5ED27 /* MTGSDKSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MTGSDKSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 5BD04DAC1E64943C00E5ED27 /* MTGSDKSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTGSDKSwift.h; sourceTree = ""; }; 81 | 5BD04DAD1E64943C00E5ED27 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | 5BD04DB21E64943C00E5ED27 /* MTGSDKSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MTGSDKSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 5BD04DB71E64943C00E5ED27 /* MTGSDKSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MTGSDKSwiftTests.swift; sourceTree = ""; }; 84 | 5BD04DB91E64943C00E5ED27 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 85 | 5BD04DC31E64945800E5ED27 /* Card.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Card.swift; sourceTree = ""; }; 86 | 5BD04DC41E64945800E5ED27 /* MTGAPIService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTGAPIService.swift; sourceTree = ""; }; 87 | 5BDF34C720854F1B007265DF /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 88 | 5BDF34CA2085500E007265DF /* MTGSearchConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MTGSearchConfiguration.swift; sourceTree = ""; }; 89 | 5BE24D1F2076D14A00EB0573 /* URLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLBuilder.swift; sourceTree = ""; }; 90 | /* End PBXFileReference section */ 91 | 92 | /* Begin PBXFrameworksBuildPhase section */ 93 | 5B87D68120596D6B0098553C /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | 5BB0E88B205FF9AA00FE67F6 /* MTGSDKSwift.framework in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | 5BD04DA51E64943C00E5ED27 /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | 5BD04DAF1E64943C00E5ED27 /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | 5BD04DB31E64943C00E5ED27 /* MTGSDKSwift.framework in Frameworks */, 113 | ); 114 | runOnlyForDeploymentPostprocessing = 0; 115 | }; 116 | /* End PBXFrameworksBuildPhase section */ 117 | 118 | /* Begin PBXGroup section */ 119 | 073F02172CCFC58D00AF05D1 /* Frameworks */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | ); 123 | name = Frameworks; 124 | sourceTree = ""; 125 | }; 126 | 5B6092D5215EA5F400CDD46A /* Recovered References */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | ); 130 | name = "Recovered References"; 131 | sourceTree = ""; 132 | }; 133 | 5B87D68520596D6B0098553C /* TestApplication */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 5B87D68620596D6B0098553C /* AppDelegate.swift */, 137 | 5B87D68820596D6B0098553C /* ViewController.swift */, 138 | 5B87D68A20596D6B0098553C /* Main.storyboard */, 139 | 5B87D68D20596D6B0098553C /* Assets.xcassets */, 140 | 5B87D68F20596D6B0098553C /* LaunchScreen.storyboard */, 141 | 5B87D69220596D6B0098553C /* Info.plist */, 142 | ); 143 | path = TestApplication; 144 | sourceTree = ""; 145 | }; 146 | 5BD04D9F1E64943C00E5ED27 = { 147 | isa = PBXGroup; 148 | children = ( 149 | 5B71E739282BED55006C7D1F /* README.md */, 150 | 5B71E73B282BEFFD006C7D1F /* Package.swift */, 151 | 5BD04DAB1E64943C00E5ED27 /* MTGSDKSwift */, 152 | 5BD04DB61E64943C00E5ED27 /* MTGSDKSwiftTests */, 153 | 5B87D68520596D6B0098553C /* TestApplication */, 154 | 5BD04DAA1E64943C00E5ED27 /* Products */, 155 | 5B6092D5215EA5F400CDD46A /* Recovered References */, 156 | 073F02172CCFC58D00AF05D1 /* Frameworks */, 157 | ); 158 | sourceTree = ""; 159 | }; 160 | 5BD04DAA1E64943C00E5ED27 /* Products */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 5BD04DA91E64943C00E5ED27 /* MTGSDKSwift.framework */, 164 | 5BD04DB21E64943C00E5ED27 /* MTGSDKSwiftTests.xctest */, 165 | 5B87D68420596D6B0098553C /* TestApplication.app */, 166 | ); 167 | name = Products; 168 | sourceTree = ""; 169 | }; 170 | 5BD04DAB1E64943C00E5ED27 /* MTGSDKSwift */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 5BDF34C920854F72007265DF /* Models */, 174 | 5BD04DAD1E64943C00E5ED27 /* Info.plist */, 175 | 5BD04DAC1E64943C00E5ED27 /* MTGSDKSwift.h */, 176 | 5BD04DC41E64945800E5ED27 /* MTGAPIService.swift */, 177 | 5BE24D1F2076D14A00EB0573 /* URLBuilder.swift */, 178 | 5BC6D7ED1E67B7A00090650A /* MagicalCardManager.swift */, 179 | ); 180 | path = MTGSDKSwift; 181 | sourceTree = ""; 182 | }; 183 | 5BD04DB61E64943C00E5ED27 /* MTGSDKSwiftTests */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 5B6092D8215EA8DF00CDD46A /* Resources */, 187 | 5BD04DB71E64943C00E5ED27 /* MTGSDKSwiftTests.swift */, 188 | 5BD04DB91E64943C00E5ED27 /* Info.plist */, 189 | ); 190 | path = MTGSDKSwiftTests; 191 | sourceTree = ""; 192 | }; 193 | 5BDF34C920854F72007265DF /* Models */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 5BDF34C720854F1B007265DF /* Constants.swift */, 197 | 5B18A9811E69EB0B0026E648 /* NetworkError.swift */, 198 | 5B6DC20B1E64A01A000DF60C /* CardSet.swift */, 199 | 5BD04DC31E64945800E5ED27 /* Card.swift */, 200 | 5B6DC20D1E64A1A0000DF60C /* SearchParameter.swift */, 201 | 5BDF34CA2085500E007265DF /* MTGSearchConfiguration.swift */, 202 | ); 203 | path = Models; 204 | sourceTree = ""; 205 | }; 206 | /* End PBXGroup section */ 207 | 208 | /* Begin PBXHeadersBuildPhase section */ 209 | 5BD04DA61E64943C00E5ED27 /* Headers */ = { 210 | isa = PBXHeadersBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | 5BD04DBA1E64943C00E5ED27 /* MTGSDKSwift.h in Headers */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXHeadersBuildPhase section */ 218 | 219 | /* Begin PBXNativeTarget section */ 220 | 5B87D68320596D6B0098553C /* TestApplication */ = { 221 | isa = PBXNativeTarget; 222 | buildConfigurationList = 5B87D69320596D6B0098553C /* Build configuration list for PBXNativeTarget "TestApplication" */; 223 | buildPhases = ( 224 | 5B87D68020596D6B0098553C /* Sources */, 225 | 5B87D68120596D6B0098553C /* Frameworks */, 226 | 5B87D68220596D6B0098553C /* Resources */, 227 | 5BB0E88F205FF9AA00FE67F6 /* Embed Frameworks */, 228 | ); 229 | buildRules = ( 230 | ); 231 | dependencies = ( 232 | 5BB0E88E205FF9AA00FE67F6 /* PBXTargetDependency */, 233 | ); 234 | name = TestApplication; 235 | productName = TestApplication; 236 | productReference = 5B87D68420596D6B0098553C /* TestApplication.app */; 237 | productType = "com.apple.product-type.application"; 238 | }; 239 | 5BD04DA81E64943C00E5ED27 /* MTGSDKSwift */ = { 240 | isa = PBXNativeTarget; 241 | buildConfigurationList = 5BD04DBD1E64943C00E5ED27 /* Build configuration list for PBXNativeTarget "MTGSDKSwift" */; 242 | buildPhases = ( 243 | 5BD04DA41E64943C00E5ED27 /* Sources */, 244 | 5BD04DA51E64943C00E5ED27 /* Frameworks */, 245 | 5BD04DA61E64943C00E5ED27 /* Headers */, 246 | 5BD04DA71E64943C00E5ED27 /* Resources */, 247 | ); 248 | buildRules = ( 249 | ); 250 | dependencies = ( 251 | ); 252 | name = MTGSDKSwift; 253 | productName = MTGSDKSwift; 254 | productReference = 5BD04DA91E64943C00E5ED27 /* MTGSDKSwift.framework */; 255 | productType = "com.apple.product-type.framework"; 256 | }; 257 | 5BD04DB11E64943C00E5ED27 /* MTGSDKSwiftTests */ = { 258 | isa = PBXNativeTarget; 259 | buildConfigurationList = 5BD04DC01E64943C00E5ED27 /* Build configuration list for PBXNativeTarget "MTGSDKSwiftTests" */; 260 | buildPhases = ( 261 | 5BD04DAE1E64943C00E5ED27 /* Sources */, 262 | 5BD04DAF1E64943C00E5ED27 /* Frameworks */, 263 | 5BD04DB01E64943C00E5ED27 /* Resources */, 264 | ); 265 | buildRules = ( 266 | ); 267 | dependencies = ( 268 | 5BD04DB51E64943C00E5ED27 /* PBXTargetDependency */, 269 | ); 270 | name = MTGSDKSwiftTests; 271 | productName = MTGSDKSwiftTests; 272 | productReference = 5BD04DB21E64943C00E5ED27 /* MTGSDKSwiftTests.xctest */; 273 | productType = "com.apple.product-type.bundle.unit-test"; 274 | }; 275 | /* End PBXNativeTarget section */ 276 | 277 | /* Begin PBXProject section */ 278 | 5BD04DA01E64943C00E5ED27 /* Project object */ = { 279 | isa = PBXProject; 280 | attributes = { 281 | LastSwiftUpdateCheck = 0910; 282 | LastUpgradeCheck = 0820; 283 | ORGANIZATIONNAME = "Reed Carson"; 284 | TargetAttributes = { 285 | 5B87D68320596D6B0098553C = { 286 | CreatedOnToolsVersion = 9.1; 287 | DevelopmentTeam = X68KF89T7U; 288 | ProvisioningStyle = Automatic; 289 | }; 290 | 5BD04DA81E64943C00E5ED27 = { 291 | CreatedOnToolsVersion = 8.2.1; 292 | ProvisioningStyle = Automatic; 293 | }; 294 | 5BD04DB11E64943C00E5ED27 = { 295 | CreatedOnToolsVersion = 8.2.1; 296 | DevelopmentTeam = X68KF89T7U; 297 | LastSwiftMigration = 0940; 298 | ProvisioningStyle = Automatic; 299 | }; 300 | }; 301 | }; 302 | buildConfigurationList = 5BD04DA31E64943C00E5ED27 /* Build configuration list for PBXProject "MTGSDKSwift" */; 303 | compatibilityVersion = "Xcode 3.2"; 304 | developmentRegion = English; 305 | hasScannedForEncodings = 0; 306 | knownRegions = ( 307 | English, 308 | en, 309 | Base, 310 | ); 311 | mainGroup = 5BD04D9F1E64943C00E5ED27; 312 | productRefGroup = 5BD04DAA1E64943C00E5ED27 /* Products */; 313 | projectDirPath = ""; 314 | projectRoot = ""; 315 | targets = ( 316 | 5BD04DA81E64943C00E5ED27 /* MTGSDKSwift */, 317 | 5BD04DB11E64943C00E5ED27 /* MTGSDKSwiftTests */, 318 | 5B87D68320596D6B0098553C /* TestApplication */, 319 | ); 320 | }; 321 | /* End PBXProject section */ 322 | 323 | /* Begin PBXResourcesBuildPhase section */ 324 | 5B87D68220596D6B0098553C /* Resources */ = { 325 | isa = PBXResourcesBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | 5B87D69120596D6B0098553C /* LaunchScreen.storyboard in Resources */, 329 | 5B87D68E20596D6B0098553C /* Assets.xcassets in Resources */, 330 | 5B87D68C20596D6B0098553C /* Main.storyboard in Resources */, 331 | ); 332 | runOnlyForDeploymentPostprocessing = 0; 333 | }; 334 | 5BD04DA71E64943C00E5ED27 /* Resources */ = { 335 | isa = PBXResourcesBuildPhase; 336 | buildActionMask = 2147483647; 337 | files = ( 338 | 5B71E73A282BED55006C7D1F /* README.md in Resources */, 339 | ); 340 | runOnlyForDeploymentPostprocessing = 0; 341 | }; 342 | 5BD04DB01E64943C00E5ED27 /* Resources */ = { 343 | isa = PBXResourcesBuildPhase; 344 | buildActionMask = 2147483647; 345 | files = ( 346 | 5B6092D9215EA8E000CDD46A /* Resources in Resources */, 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | }; 350 | /* End PBXResourcesBuildPhase section */ 351 | 352 | /* Begin PBXSourcesBuildPhase section */ 353 | 5B87D68020596D6B0098553C /* Sources */ = { 354 | isa = PBXSourcesBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | 5B87D68920596D6B0098553C /* ViewController.swift in Sources */, 358 | 5B87D68720596D6B0098553C /* AppDelegate.swift in Sources */, 359 | ); 360 | runOnlyForDeploymentPostprocessing = 0; 361 | }; 362 | 5BD04DA41E64943C00E5ED27 /* Sources */ = { 363 | isa = PBXSourcesBuildPhase; 364 | buildActionMask = 2147483647; 365 | files = ( 366 | 5BC6D7EE1E67B7A00090650A /* MagicalCardManager.swift in Sources */, 367 | 5B18A9821E69EB0B0026E648 /* NetworkError.swift in Sources */, 368 | 5BD04DC51E64945800E5ED27 /* Card.swift in Sources */, 369 | 5BD04DC61E64945800E5ED27 /* MTGAPIService.swift in Sources */, 370 | 5B6DC20E1E64A1A0000DF60C /* SearchParameter.swift in Sources */, 371 | 5BDF34CB2085500E007265DF /* MTGSearchConfiguration.swift in Sources */, 372 | 5BE24D202076D14A00EB0573 /* URLBuilder.swift in Sources */, 373 | 5B6DC20C1E64A01A000DF60C /* CardSet.swift in Sources */, 374 | 5BDF34C820854F1B007265DF /* Constants.swift in Sources */, 375 | ); 376 | runOnlyForDeploymentPostprocessing = 0; 377 | }; 378 | 5BD04DAE1E64943C00E5ED27 /* Sources */ = { 379 | isa = PBXSourcesBuildPhase; 380 | buildActionMask = 2147483647; 381 | files = ( 382 | 5BD04DB81E64943C00E5ED27 /* MTGSDKSwiftTests.swift in Sources */, 383 | ); 384 | runOnlyForDeploymentPostprocessing = 0; 385 | }; 386 | /* End PBXSourcesBuildPhase section */ 387 | 388 | /* Begin PBXTargetDependency section */ 389 | 5BB0E88E205FF9AA00FE67F6 /* PBXTargetDependency */ = { 390 | isa = PBXTargetDependency; 391 | target = 5BD04DA81E64943C00E5ED27 /* MTGSDKSwift */; 392 | targetProxy = 5BB0E88D205FF9AA00FE67F6 /* PBXContainerItemProxy */; 393 | }; 394 | 5BD04DB51E64943C00E5ED27 /* PBXTargetDependency */ = { 395 | isa = PBXTargetDependency; 396 | target = 5BD04DA81E64943C00E5ED27 /* MTGSDKSwift */; 397 | targetProxy = 5BD04DB41E64943C00E5ED27 /* PBXContainerItemProxy */; 398 | }; 399 | /* End PBXTargetDependency section */ 400 | 401 | /* Begin PBXVariantGroup section */ 402 | 5B87D68A20596D6B0098553C /* Main.storyboard */ = { 403 | isa = PBXVariantGroup; 404 | children = ( 405 | 5B87D68B20596D6B0098553C /* Base */, 406 | ); 407 | name = Main.storyboard; 408 | sourceTree = ""; 409 | }; 410 | 5B87D68F20596D6B0098553C /* LaunchScreen.storyboard */ = { 411 | isa = PBXVariantGroup; 412 | children = ( 413 | 5B87D69020596D6B0098553C /* Base */, 414 | ); 415 | name = LaunchScreen.storyboard; 416 | sourceTree = ""; 417 | }; 418 | /* End PBXVariantGroup section */ 419 | 420 | /* Begin XCBuildConfiguration section */ 421 | 5B87D69420596D6B0098553C /* Debug */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 425 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 426 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 427 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 428 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 429 | CLANG_WARN_COMMA = YES; 430 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 431 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 432 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 433 | CLANG_WARN_STRICT_PROTOTYPES = YES; 434 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 435 | CODE_SIGN_IDENTITY = "iPhone Developer"; 436 | CODE_SIGN_STYLE = Automatic; 437 | DEVELOPMENT_TEAM = X68KF89T7U; 438 | GCC_C_LANGUAGE_STANDARD = gnu11; 439 | INFOPLIST_FILE = TestApplication/Info.plist; 440 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 441 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 442 | PRODUCT_BUNDLE_IDENTIFIER = com.rpcarson.MTGSDKSwift.Test; 443 | PRODUCT_NAME = "$(TARGET_NAME)"; 444 | SWIFT_VERSION = 4.0; 445 | TARGETED_DEVICE_FAMILY = "1,2"; 446 | }; 447 | name = Debug; 448 | }; 449 | 5B87D69520596D6B0098553C /* Release */ = { 450 | isa = XCBuildConfiguration; 451 | buildSettings = { 452 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 453 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 454 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 455 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 456 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 457 | CLANG_WARN_COMMA = YES; 458 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 459 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 460 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 461 | CLANG_WARN_STRICT_PROTOTYPES = YES; 462 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 463 | CODE_SIGN_IDENTITY = "iPhone Developer"; 464 | CODE_SIGN_STYLE = Automatic; 465 | DEVELOPMENT_TEAM = X68KF89T7U; 466 | GCC_C_LANGUAGE_STANDARD = gnu11; 467 | INFOPLIST_FILE = TestApplication/Info.plist; 468 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 470 | PRODUCT_BUNDLE_IDENTIFIER = com.rpcarson.MTGSDKSwift.Test; 471 | PRODUCT_NAME = "$(TARGET_NAME)"; 472 | SWIFT_VERSION = 4.0; 473 | TARGETED_DEVICE_FAMILY = "1,2"; 474 | }; 475 | name = Release; 476 | }; 477 | 5BD04DBB1E64943C00E5ED27 /* Debug */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | ALWAYS_SEARCH_USER_PATHS = NO; 481 | CLANG_ANALYZER_NONNULL = YES; 482 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 483 | CLANG_CXX_LIBRARY = "libc++"; 484 | CLANG_ENABLE_MODULES = YES; 485 | CLANG_ENABLE_OBJC_ARC = YES; 486 | CLANG_WARN_BOOL_CONVERSION = YES; 487 | CLANG_WARN_CONSTANT_CONVERSION = YES; 488 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 489 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 490 | CLANG_WARN_EMPTY_BODY = YES; 491 | CLANG_WARN_ENUM_CONVERSION = YES; 492 | CLANG_WARN_INFINITE_RECURSION = YES; 493 | CLANG_WARN_INT_CONVERSION = YES; 494 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 495 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 496 | CLANG_WARN_UNREACHABLE_CODE = YES; 497 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 498 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 499 | COPY_PHASE_STRIP = NO; 500 | CURRENT_PROJECT_VERSION = 1; 501 | DEBUG_INFORMATION_FORMAT = dwarf; 502 | ENABLE_STRICT_OBJC_MSGSEND = YES; 503 | ENABLE_TESTABILITY = YES; 504 | GCC_C_LANGUAGE_STANDARD = gnu99; 505 | GCC_DYNAMIC_NO_PIC = NO; 506 | GCC_NO_COMMON_BLOCKS = YES; 507 | GCC_OPTIMIZATION_LEVEL = 0; 508 | GCC_PREPROCESSOR_DEFINITIONS = ( 509 | "DEBUG=1", 510 | "$(inherited)", 511 | ); 512 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 513 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 514 | GCC_WARN_UNDECLARED_SELECTOR = YES; 515 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 516 | GCC_WARN_UNUSED_FUNCTION = YES; 517 | GCC_WARN_UNUSED_VARIABLE = YES; 518 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 519 | MTL_ENABLE_DEBUG_INFO = YES; 520 | ONLY_ACTIVE_ARCH = YES; 521 | SDKROOT = iphoneos; 522 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 523 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 524 | TARGETED_DEVICE_FAMILY = "1,2"; 525 | VERSIONING_SYSTEM = "apple-generic"; 526 | VERSION_INFO_PREFIX = ""; 527 | }; 528 | name = Debug; 529 | }; 530 | 5BD04DBC1E64943C00E5ED27 /* Release */ = { 531 | isa = XCBuildConfiguration; 532 | buildSettings = { 533 | ALWAYS_SEARCH_USER_PATHS = NO; 534 | CLANG_ANALYZER_NONNULL = YES; 535 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 536 | CLANG_CXX_LIBRARY = "libc++"; 537 | CLANG_ENABLE_MODULES = YES; 538 | CLANG_ENABLE_OBJC_ARC = YES; 539 | CLANG_WARN_BOOL_CONVERSION = YES; 540 | CLANG_WARN_CONSTANT_CONVERSION = YES; 541 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 542 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 543 | CLANG_WARN_EMPTY_BODY = YES; 544 | CLANG_WARN_ENUM_CONVERSION = YES; 545 | CLANG_WARN_INFINITE_RECURSION = YES; 546 | CLANG_WARN_INT_CONVERSION = YES; 547 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 548 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 549 | CLANG_WARN_UNREACHABLE_CODE = YES; 550 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 551 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 552 | COPY_PHASE_STRIP = NO; 553 | CURRENT_PROJECT_VERSION = 1; 554 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 555 | ENABLE_NS_ASSERTIONS = NO; 556 | ENABLE_STRICT_OBJC_MSGSEND = YES; 557 | GCC_C_LANGUAGE_STANDARD = gnu99; 558 | GCC_NO_COMMON_BLOCKS = YES; 559 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 560 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 561 | GCC_WARN_UNDECLARED_SELECTOR = YES; 562 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 563 | GCC_WARN_UNUSED_FUNCTION = YES; 564 | GCC_WARN_UNUSED_VARIABLE = YES; 565 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 566 | MTL_ENABLE_DEBUG_INFO = NO; 567 | SDKROOT = iphoneos; 568 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 569 | TARGETED_DEVICE_FAMILY = "1,2"; 570 | VALIDATE_PRODUCT = YES; 571 | VERSIONING_SYSTEM = "apple-generic"; 572 | VERSION_INFO_PREFIX = ""; 573 | }; 574 | name = Release; 575 | }; 576 | 5BD04DBE1E64943C00E5ED27 /* Debug */ = { 577 | isa = XCBuildConfiguration; 578 | buildSettings = { 579 | CODE_SIGN_IDENTITY = "iPhone Developer"; 580 | DEFINES_MODULE = YES; 581 | DEVELOPMENT_TEAM = ""; 582 | DYLIB_COMPATIBILITY_VERSION = 1; 583 | DYLIB_CURRENT_VERSION = 1; 584 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 585 | INFOPLIST_FILE = MTGSDKSwift/Info.plist; 586 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 587 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 588 | LD_RUNPATH_SEARCH_PATHS = ( 589 | "$(inherited)", 590 | "@executable_path/Frameworks", 591 | "@loader_path/Frameworks", 592 | ); 593 | MACOSX_DEPLOYMENT_TARGET = 12.4; 594 | MARKETING_VERSION = 1.1.1; 595 | PRODUCT_BUNDLE_IDENTIFIER = com.rpcarson.MTGSDKSwift; 596 | PRODUCT_NAME = "$(TARGET_NAME)"; 597 | REGISTER_APP_GROUPS = NO; 598 | SKIP_INSTALL = YES; 599 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 600 | SUPPORTS_MACCATALYST = YES; 601 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 602 | SWIFT_VERSION = 4.0; 603 | TARGETED_DEVICE_FAMILY = "1,2"; 604 | }; 605 | name = Debug; 606 | }; 607 | 5BD04DBF1E64943C00E5ED27 /* Release */ = { 608 | isa = XCBuildConfiguration; 609 | buildSettings = { 610 | CODE_SIGN_IDENTITY = "iPhone Developer"; 611 | DEFINES_MODULE = YES; 612 | DEVELOPMENT_TEAM = ""; 613 | DYLIB_COMPATIBILITY_VERSION = 1; 614 | DYLIB_CURRENT_VERSION = 1; 615 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 616 | INFOPLIST_FILE = MTGSDKSwift/Info.plist; 617 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 618 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 619 | LD_RUNPATH_SEARCH_PATHS = ( 620 | "$(inherited)", 621 | "@executable_path/Frameworks", 622 | "@loader_path/Frameworks", 623 | ); 624 | MACOSX_DEPLOYMENT_TARGET = 12.4; 625 | MARKETING_VERSION = 1.1.1; 626 | PRODUCT_BUNDLE_IDENTIFIER = com.rpcarson.MTGSDKSwift; 627 | PRODUCT_NAME = "$(TARGET_NAME)"; 628 | REGISTER_APP_GROUPS = NO; 629 | SKIP_INSTALL = YES; 630 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 631 | SUPPORTS_MACCATALYST = YES; 632 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 633 | SWIFT_VERSION = 4.0; 634 | TARGETED_DEVICE_FAMILY = "1,2"; 635 | }; 636 | name = Release; 637 | }; 638 | 5BD04DC11E64943C00E5ED27 /* Debug */ = { 639 | isa = XCBuildConfiguration; 640 | buildSettings = { 641 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 642 | DEVELOPMENT_TEAM = X68KF89T7U; 643 | INFOPLIST_FILE = MTGSDKSwiftTests/Info.plist; 644 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 645 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 646 | PRODUCT_BUNDLE_IDENTIFIER = com.rpcarson.MTGSDKSwiftTests; 647 | PRODUCT_NAME = "$(TARGET_NAME)"; 648 | REGISTER_APP_GROUPS = NO; 649 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 650 | SUPPORTS_MACCATALYST = YES; 651 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 652 | SWIFT_VERSION = 4.0; 653 | TARGETED_DEVICE_FAMILY = "1,2"; 654 | }; 655 | name = Debug; 656 | }; 657 | 5BD04DC21E64943C00E5ED27 /* Release */ = { 658 | isa = XCBuildConfiguration; 659 | buildSettings = { 660 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 661 | DEVELOPMENT_TEAM = X68KF89T7U; 662 | INFOPLIST_FILE = MTGSDKSwiftTests/Info.plist; 663 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 664 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 665 | PRODUCT_BUNDLE_IDENTIFIER = com.rpcarson.MTGSDKSwiftTests; 666 | PRODUCT_NAME = "$(TARGET_NAME)"; 667 | REGISTER_APP_GROUPS = NO; 668 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 669 | SUPPORTS_MACCATALYST = YES; 670 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 671 | SWIFT_VERSION = 4.0; 672 | TARGETED_DEVICE_FAMILY = "1,2"; 673 | }; 674 | name = Release; 675 | }; 676 | /* End XCBuildConfiguration section */ 677 | 678 | /* Begin XCConfigurationList section */ 679 | 5B87D69320596D6B0098553C /* Build configuration list for PBXNativeTarget "TestApplication" */ = { 680 | isa = XCConfigurationList; 681 | buildConfigurations = ( 682 | 5B87D69420596D6B0098553C /* Debug */, 683 | 5B87D69520596D6B0098553C /* Release */, 684 | ); 685 | defaultConfigurationIsVisible = 0; 686 | defaultConfigurationName = Release; 687 | }; 688 | 5BD04DA31E64943C00E5ED27 /* Build configuration list for PBXProject "MTGSDKSwift" */ = { 689 | isa = XCConfigurationList; 690 | buildConfigurations = ( 691 | 5BD04DBB1E64943C00E5ED27 /* Debug */, 692 | 5BD04DBC1E64943C00E5ED27 /* Release */, 693 | ); 694 | defaultConfigurationIsVisible = 0; 695 | defaultConfigurationName = Release; 696 | }; 697 | 5BD04DBD1E64943C00E5ED27 /* Build configuration list for PBXNativeTarget "MTGSDKSwift" */ = { 698 | isa = XCConfigurationList; 699 | buildConfigurations = ( 700 | 5BD04DBE1E64943C00E5ED27 /* Debug */, 701 | 5BD04DBF1E64943C00E5ED27 /* Release */, 702 | ); 703 | defaultConfigurationIsVisible = 0; 704 | defaultConfigurationName = Release; 705 | }; 706 | 5BD04DC01E64943C00E5ED27 /* Build configuration list for PBXNativeTarget "MTGSDKSwiftTests" */ = { 707 | isa = XCConfigurationList; 708 | buildConfigurations = ( 709 | 5BD04DC11E64943C00E5ED27 /* Debug */, 710 | 5BD04DC21E64943C00E5ED27 /* Release */, 711 | ); 712 | defaultConfigurationIsVisible = 0; 713 | defaultConfigurationName = Release; 714 | }; 715 | /* End XCConfigurationList section */ 716 | }; 717 | rootObject = 5BD04DA01E64943C00E5ED27 /* Project object */; 718 | } 719 | --------------------------------------------------------------------------------