diff --git a/Cores/DeltaCore b/Cores/DeltaCore index caaf2e8..f33f8bd 160000 --- a/Cores/DeltaCore +++ b/Cores/DeltaCore @@ -1 +1 @@ -Subproject commit caaf2e8e4bd847a2442382e121b07b4d5f139000 +Subproject commit f33f8bd91a9e0b41ba55b9aa8370397dd7e7f809 diff --git a/Cores/GBADeltaCore b/Cores/GBADeltaCore index 4eedbd4..56401b9 160000 --- a/Cores/GBADeltaCore +++ b/Cores/GBADeltaCore @@ -1 +1 @@ -Subproject commit 4eedbd481457e3c236d1f3ffab3ba2f49c6d18df +Subproject commit 56401b9649f8abe971e3a66be1a3bb2cd984a1a0 diff --git a/Cores/GBCDeltaCore b/Cores/GBCDeltaCore index 0e622c7..4e678e7 160000 --- a/Cores/GBCDeltaCore +++ b/Cores/GBCDeltaCore @@ -1 +1 @@ -Subproject commit 0e622c7887e781363e36f6c7bfcd67fba3cb00ac +Subproject commit 4e678e7eac511d342aab86522eede9fdb7b29108 diff --git a/Cores/SNESDeltaCore b/Cores/SNESDeltaCore index bdc95ae..3946277 160000 --- a/Cores/SNESDeltaCore +++ b/Cores/SNESDeltaCore @@ -1 +1 @@ -Subproject commit bdc95aeb5e7f50263c34187cbe38ddddb4a2576e +Subproject commit 394627784bd0643c26e0fc95feafa5c960786a7c diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index 07ef994..7c280a9 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ BF1173501DA32CF600047DF8 /* ControllersSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF11734F1DA32CF600047DF8 /* ControllersSettingsViewController.swift */; }; BF13A7561D5D29B0000BB055 /* PreviewGameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF13A7551D5D29B0000BB055 /* PreviewGameViewController.swift */; }; BF13A7581D5D2FD9000BB055 /* EmulatorCore+Cheats.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF13A7571D5D2FD9000BB055 /* EmulatorCore+Cheats.swift */; }; + BF15AF841F54B43B009B6AAB /* ActionInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF15AF831F54B43B009B6AAB /* ActionInput.swift */; }; BF18B61F1E2985F900F70067 /* UIAlertController+Importing.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18B61E1E2985F900F70067 /* UIAlertController+Importing.swift */; }; BF1DAD5D1D9F576000E752A7 /* SystemControllerSkinsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1DAD5C1D9F576000E752A7 /* SystemControllerSkinsViewController.swift */; }; BF27CC8E1BC9FEA200A20D89 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF6BB2451BB73FE800CCF94A /* Assets.xcassets */; }; @@ -39,7 +40,7 @@ BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF34FA101CF1899D006624C7 /* CheatTextView.swift */; }; BF353FF21C5D7FB000C1184C /* PauseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF353FF11C5D7FB000C1184C /* PauseViewController.swift */; }; BF353FF61C5D837600C1184C /* PauseMenu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF353FF41C5D837600C1184C /* PauseMenu.storyboard */; }; - BF353FF91C5D870B00C1184C /* PauseItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF353FF81C5D870B00C1184C /* PauseItem.swift */; }; + BF353FF91C5D870B00C1184C /* MenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF353FF81C5D870B00C1184C /* MenuItem.swift */; }; BF353FFF1C5DA3C500C1184C /* PausePresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF353FFD1C5DA3C500C1184C /* PausePresentationController.swift */; }; BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF353FFE1C5DA3C500C1184C /* PausePresentationControllerContentView.xib */; }; BF3540021C5DA3D500C1184C /* PauseStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540011C5DA3D500C1184C /* PauseStoryboardSegue.swift */; }; @@ -68,6 +69,8 @@ BF5942951E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942921E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift */; }; BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */; }; BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BF5E7F451B9A652600AE44F8 /* Settings.storyboard */; }; + BF6424831F5B8F3F00D6AB44 /* ListMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6424821F5B8F3F00D6AB44 /* ListMenuViewController.swift */; }; + BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6424841F5CBDC900D6AB44 /* UIView+ParentViewController.swift */; }; BF6866171DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6866161DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift */; }; BF696B801D9B2B02009639E0 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF696B7F1D9B2B02009639E0 /* Theme.swift */; }; BF6BF3131EB7E47F008E83CD /* ImportOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6BF3121EB7E47F008E83CD /* ImportOption.swift */; }; @@ -79,8 +82,11 @@ BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; }; BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */; }; - BF7AE8081C2E858400B1B5BC /* PauseMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8041C2E858400B1B5BC /* PauseMenuViewController.swift */; }; + BF7AE8081C2E858400B1B5BC /* GridMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8041C2E858400B1B5BC /* GridMenuViewController.swift */; }; BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */; }; + BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF616A121F08184A0077F8B2 /* ControllerInputsViewController.swift */; }; + BF8CA9361F5F651900499FDD /* PopoverMenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CA9351F5F651900499FDD /* PopoverMenuController.swift */; }; + BF8DDD241F4F6C880088A21B /* InputCalloutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8DDD231F4F6C880088A21B /* InputCalloutView.swift */; }; BF930FFD1EB6D6FF00E8DBA0 /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF930FFC1EB6D6FF00E8DBA0 /* System.swift */; }; BF95E2771E4977BF0030E7AD /* GameMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF95E2761E4977BF0030E7AD /* GameMetadata.swift */; }; BF95E2791E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF95E2781E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift */; }; @@ -92,10 +98,12 @@ BFA0D1271D3AE1F600565894 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF63BDE91D389EEB00FCB040 /* GameViewController.swift */; }; BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFAA1FEC1B8AA4FA00495943 /* Settings.swift */; }; BFBAB2E31EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBAB2E21EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift */; }; + BFC6F7B81F435BC500221B96 /* Input+Display.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC6F7B71F435BC500221B96 /* Input+Display.swift */; }; BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */; }; BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */; }; BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540041C5DA70400C1184C /* SaveStatesViewController.swift */; }; BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */; }; + BFE022A01F5B57FF0052D888 /* PopoverMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */; }; BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */; }; BFEC732D1AAECC4A00650035 /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; }; BFEC732E1AAECC4A00650035 /* Roxas.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -144,6 +152,7 @@ BF11734F1DA32CF600047DF8 /* ControllersSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControllersSettingsViewController.swift; path = Controllers/ControllersSettingsViewController.swift; sourceTree = ""; }; BF13A7551D5D29B0000BB055 /* PreviewGameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewGameViewController.swift; sourceTree = ""; }; BF13A7571D5D2FD9000BB055 /* EmulatorCore+Cheats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EmulatorCore+Cheats.swift"; sourceTree = ""; }; + BF15AF831F54B43B009B6AAB /* ActionInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionInput.swift; sourceTree = ""; }; BF18B61E1E2985F900F70067 /* UIAlertController+Importing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Importing.swift"; sourceTree = ""; }; BF1DAD5C1D9F576000E752A7 /* SystemControllerSkinsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SystemControllerSkinsViewController.swift; path = "Controller Skins/SystemControllerSkinsViewController.swift"; sourceTree = ""; }; BF27CC861BC9E3C600A20D89 /* Delta.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Delta.entitlements; sourceTree = ""; }; @@ -155,7 +164,7 @@ BF34FA101CF1899D006624C7 /* CheatTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatTextView.swift; path = "Pause Menu/Cheats/CheatTextView.swift"; sourceTree = ""; }; BF353FF11C5D7FB000C1184C /* PauseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseViewController.swift; path = "Pause Menu/PauseViewController.swift"; sourceTree = ""; }; BF353FF51C5D837600C1184C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/PauseMenu.storyboard; sourceTree = ""; }; - BF353FF81C5D870B00C1184C /* PauseItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseItem.swift; path = "Pause Menu/PauseItem.swift"; sourceTree = ""; }; + BF353FF81C5D870B00C1184C /* MenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MenuItem.swift; path = "Pause Menu/MenuItem.swift"; sourceTree = ""; }; BF353FFD1C5DA3C500C1184C /* PausePresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PausePresentationController.swift; path = "Pause Menu/Presentation Controller/PausePresentationController.swift"; sourceTree = ""; }; BF353FFE1C5DA3C500C1184C /* PausePresentationControllerContentView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = PausePresentationControllerContentView.xib; path = "Pause Menu/Presentation Controller/PausePresentationControllerContentView.xib"; sourceTree = ""; }; BF3540011C5DA3D500C1184C /* PauseStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseStoryboardSegue.swift; path = "Pause Menu/Segues/PauseStoryboardSegue.swift"; sourceTree = ""; }; @@ -187,7 +196,10 @@ BF5942921E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Conveniences.swift"; sourceTree = ""; }; BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; BF5E7F451B9A652600AE44F8 /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; + BF616A121F08184A0077F8B2 /* ControllerInputsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ControllerInputsViewController.swift; path = Controllers/ControllerInputsViewController.swift; sourceTree = ""; }; BF63BDE91D389EEB00FCB040 /* GameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; + BF6424821F5B8F3F00D6AB44 /* ListMenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ListMenuViewController.swift; path = "Components/Popover Menu/ListMenuViewController.swift"; sourceTree = ""; }; + BF6424841F5CBDC900D6AB44 /* UIView+ParentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+ParentViewController.swift"; sourceTree = ""; }; BF6866161DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ControllerSkin+Configuring.swift"; sourceTree = ""; }; BF696B7F1D9B2B02009639E0 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Theme.swift; path = Theming/Theme.swift; sourceTree = ""; }; BF6BB2451BB73FE800CCF94A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -199,8 +211,10 @@ BF6BF3261EB87EB8008E83CD /* PhotoLibraryImportOption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PhotoLibraryImportOption.swift; path = "Importing/Import Options/PhotoLibraryImportOption.swift"; sourceTree = ""; }; BF70798B1B6B464B0019077C /* ZipZap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ZipZap.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILabel+FontSize.swift"; sourceTree = ""; }; - BF7AE8041C2E858400B1B5BC /* PauseMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PauseMenuViewController.swift; path = "Pause Menu/PauseMenuViewController.swift"; sourceTree = ""; }; + BF7AE8041C2E858400B1B5BC /* GridMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GridMenuViewController.swift; path = "Pause Menu/GridMenuViewController.swift"; sourceTree = ""; }; BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Delta.swift"; sourceTree = ""; }; + BF8CA9351F5F651900499FDD /* PopoverMenuController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PopoverMenuController.swift; path = "Components/Popover Menu/PopoverMenuController.swift"; sourceTree = ""; }; + BF8DDD231F4F6C880088A21B /* InputCalloutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = InputCalloutView.swift; path = Controllers/InputCalloutView.swift; sourceTree = ""; }; BF930FFC1EB6D6FF00E8DBA0 /* System.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = System.swift; path = Systems/System.swift; sourceTree = ""; }; BF95E2761E4977BF0030E7AD /* GameMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameMetadata.swift; path = Database/OpenVGDB/GameMetadata.swift; sourceTree = ""; }; BF95E2781E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GamesDatabaseBrowserViewController.swift; path = Database/OpenVGDB/GamesDatabaseBrowserViewController.swift; sourceTree = ""; }; @@ -209,9 +223,11 @@ BFAA1FEC1B8AA4FA00495943 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; BFBAB2E21EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DeltaCoreProtocol+Delta.swift"; sourceTree = ""; }; BFC134E01AAD82460087AD7B /* SNESDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SNESDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BFC6F7B71F435BC500221B96 /* Input+Display.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Input+Display.swift"; sourceTree = ""; }; BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatsViewController.swift; path = "Pause Menu/Cheats/CheatsViewController.swift"; sourceTree = ""; }; BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewControllerContextTransitioning+Conveniences.swift"; sourceTree = ""; }; BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = ""; }; + BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PopoverMenuButton.swift; path = "Components/Popover Menu/PopoverMenuButton.swift"; sourceTree = ""; }; BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SaveStatesStoryboardSegue.swift; path = Segues/SaveStatesStoryboardSegue.swift; sourceTree = ""; }; BFEC732C1AAECC4A00650035 /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBCDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -262,6 +278,8 @@ BF5942921E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift */, BFBAB2E21EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift */, BF18B61E1E2985F900F70067 /* UIAlertController+Importing.swift */, + BFC6F7B71F435BC500221B96 /* Input+Display.swift */, + BF6424841F5CBDC900D6AB44 /* UIView+ParentViewController.swift */, ); path = Extensions; sourceTree = ""; @@ -270,6 +288,8 @@ isa = PBXGroup; children = ( BF11734F1DA32CF600047DF8 /* ControllersSettingsViewController.swift */, + BF616A121F08184A0077F8B2 /* ControllerInputsViewController.swift */, + BF8DDD231F4F6C880088A21B /* InputCalloutView.swift */, ); name = Controllers; sourceTree = ""; @@ -316,6 +336,7 @@ isa = PBXGroup; children = ( BF5942581E09BB810051894B /* Action.swift */, + BFE0229C1F5B56840052D888 /* Popover Menu */, BF5942671E09BBB70051894B /* Collection View */, BF5942601E09BBA80051894B /* Loading */, ); @@ -428,8 +449,8 @@ children = ( BF353FF41C5D837600C1184C /* PauseMenu.storyboard */, BF353FF11C5D7FB000C1184C /* PauseViewController.swift */, - BF7AE8041C2E858400B1B5BC /* PauseMenuViewController.swift */, - BF353FF81C5D870B00C1184C /* PauseItem.swift */, + BF7AE8041C2E858400B1B5BC /* GridMenuViewController.swift */, + BF353FF81C5D870B00C1184C /* MenuItem.swift */, BF3540031C5DA6D800C1184C /* Save States */, BFC9B7371CEFCD08008629BB /* Cheats */, BF353FFB1C5DA2F600C1184C /* Presentation Controller */, @@ -508,6 +529,16 @@ name = Cheats; sourceTree = ""; }; + BFE0229C1F5B56840052D888 /* Popover Menu */ = { + isa = PBXGroup; + children = ( + BF8CA9351F5F651900499FDD /* PopoverMenuController.swift */, + BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */, + BF6424821F5B8F3F00D6AB44 /* ListMenuViewController.swift */, + ); + name = "Popover Menu"; + sourceTree = ""; + }; BFEC732F1AAECCBD00650035 /* Resources */ = { isa = PBXGroup; children = ( @@ -521,8 +552,8 @@ isa = PBXGroup; children = ( BFFA71D91AAC406100EE9DD1 /* Delta */, - BFEC732F1AAECCBD00650035 /* Resources */, BF9F4FCD1AAD7B25004C9500 /* Frameworks */, + BFEC732F1AAECCBD00650035 /* Resources */, BFFA71D81AAC406100EE9DD1 /* Products */, FD1E8AE87FA2DB8793F7B937 /* Pods */, ); @@ -572,6 +603,7 @@ children = ( BF63BDE91D389EEB00FCB040 /* GameViewController.swift */, BF13A7551D5D29B0000BB055 /* PreviewGameViewController.swift */, + BF15AF831F54B43B009B6AAB /* ActionInput.swift */, ); path = Emulation; sourceTree = ""; @@ -776,6 +808,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + BFC6F7B81F435BC500221B96 /* Input+Display.swift in Sources */, BF59426A1E09BBD00051894B /* GridCollectionViewCell.swift in Sources */, BF6BF3181EB82111008E83CD /* iTunesImportOption.swift in Sources */, BF59427C1E09BC830051894B /* Cheat.swift in Sources */, @@ -789,24 +822,29 @@ BF59428E1E09BCFB0051894B /* ImportController.swift in Sources */, BF930FFD1EB6D6FF00E8DBA0 /* System.swift in Sources */, BF13A7581D5D2FD9000BB055 /* EmulatorCore+Cheats.swift in Sources */, + BF6424831F5B8F3F00D6AB44 /* ListMenuViewController.swift in Sources */, BF6BF3131EB7E47F008E83CD /* ImportOption.swift in Sources */, BF31878B1D489AAA00BD020D /* CheatValidator.swift in Sources */, BFFC46201D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift in Sources */, BF5942731E09BC700051894B /* Model.xcdatamodel in Sources */, + BF15AF841F54B43B009B6AAB /* ActionInput.swift in Sources */, BF5942951E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift in Sources */, - BF353FF91C5D870B00C1184C /* PauseItem.swift in Sources */, + BF353FF91C5D870B00C1184C /* MenuItem.swift in Sources */, BF18B61F1E2985F900F70067 /* UIAlertController+Importing.swift in Sources */, BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */, BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */, BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */, BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */, + BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */, BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */, BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */, BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */, BF1DAD5D1D9F576000E752A7 /* SystemControllerSkinsViewController.swift in Sources */, + BFE022A01F5B57FF0052D888 /* PopoverMenuButton.swift in Sources */, BF6BF31C1EB821A0008E83CD /* GamesDatabaseImportOption.swift in Sources */, BFFA4C091E8A24D600D87934 /* GameMetadataTableViewCell.swift in Sources */, BFFC46231D5984A000AF2CC6 /* LaunchViewController.swift in Sources */, + BF8DDD241F4F6C880088A21B /* InputCalloutView.swift in Sources */, BF5942701E09BC5D0051894B /* GamesDatabase.swift in Sources */, BF34FA071CF0F510006624C7 /* EditCheatViewController.swift in Sources */, BF5942881E09BC8B0051894B /* _Game.swift in Sources */, @@ -819,6 +857,7 @@ BF5942941E09BD1A0051894B /* NSManagedObject+Conveniences.swift in Sources */, BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */, BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */, + BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */, BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */, BF5942871E09BC8B0051894B /* _ControllerSkin.swift in Sources */, BF95E2791E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift in Sources */, @@ -835,13 +874,14 @@ BF99A5971DC2F9C400468E9E /* ControllerSkinTableViewCell.swift in Sources */, BF5942861E09BC8B0051894B /* _Cheat.swift in Sources */, BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */, + BF8CA9361F5F651900499FDD /* PopoverMenuController.swift in Sources */, BF5942931E09BD1A0051894B /* NSFetchedResultsController+Conveniences.m in Sources */, BF6BF3271EB87EB8008E83CD /* PhotoLibraryImportOption.swift in Sources */, BF5942661E09BBB10051894B /* LoadImageURLOperation.swift in Sources */, BF353FF21C5D7FB000C1184C /* PauseViewController.swift in Sources */, BF59425C1E09BB810051894B /* Action.swift in Sources */, BF696B801D9B2B02009639E0 /* Theme.swift in Sources */, - BF7AE8081C2E858400B1B5BC /* PauseMenuViewController.swift in Sources */, + BF7AE8081C2E858400B1B5BC /* GridMenuViewController.swift in Sources */, BF6BF31A1EB82146008E83CD /* ClipboardImportOption.swift in Sources */, BFF93AA01E0FB036005EC865 /* InputStreamOutputWriter.swift in Sources */, BF59427F1E09BC830051894B /* GameCollection.swift in Sources */, diff --git a/Delta/AppDelegate.swift b/Delta/AppDelegate.swift index 4277f48..99c9a35 100644 --- a/Delta/AppDelegate.swift +++ b/Delta/AppDelegate.swift @@ -40,7 +40,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate } // Controllers - ExternalControllerManager.shared.startMonitoringExternalControllers() + ExternalGameControllerManager.shared.startMonitoring() return true } diff --git a/Delta/Base.lproj/PauseMenu.storyboard b/Delta/Base.lproj/PauseMenu.storyboard index 93db1ba..e6ced72 100644 --- a/Delta/Base.lproj/PauseMenu.storyboard +++ b/Delta/Base.lproj/PauseMenu.storyboard @@ -1,11 +1,15 @@ - - + + - - + + + + Menlo-Regular + + @@ -16,15 +20,17 @@ - + + - + + @@ -63,7 +69,7 @@ - + @@ -78,9 +84,9 @@ - - - + + + @@ -91,7 +97,7 @@ - + @@ -128,7 +134,7 @@ - + @@ -139,7 +145,7 @@ - + @@ -148,7 +154,7 @@ - + @@ -174,22 +180,22 @@ - + - + - + - + - + @@ -198,8 +204,9 @@ + - + @@ -245,20 +252,21 @@ - + - + - + + @@ -280,13 +288,14 @@ - + - + + @@ -308,13 +317,14 @@ - + - + + diff --git a/Delta/Components/Popover Menu/ListMenuViewController.swift b/Delta/Components/Popover Menu/ListMenuViewController.swift new file mode 100644 index 0000000..88bd43f --- /dev/null +++ b/Delta/Components/Popover Menu/ListMenuViewController.swift @@ -0,0 +1,64 @@ +// +// PopoverMenuViewController.swift +// Delta +// +// Created by Riley Testut on 9/2/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import UIKit + +import Roxas + +class ListMenuViewController: UITableViewController +{ + var items: [MenuItem] { + get { return self.dataSource.items } + set { self.dataSource.items = newValue } + } + + fileprivate let dataSource = RSTArrayTableViewDataSource(items: []) + + override var preferredContentSize: CGSize { + get { + let navigationBarHeight = self.navigationController?.navigationBar.bounds.height ?? 0.0 + return CGSize(width: 0, height: (self.tableView.rowHeight * CGFloat(self.items.count)) + navigationBarHeight) + } + set {} + } + + init() + { + super.init(style: .plain) + + self.dataSource.cellConfigurationHandler = { (cell, item, indexPath) in + cell.textLabel?.text = item.text + cell.accessoryType = item.isSelected ? .checkmark : .none + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() + { + super.viewDidLoad() + + self.tableView.dataSource = self.dataSource + self.tableView.rowHeight = 44 + self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: RSTCellContentGenericCellIdentifier) + } +} + +extension ListMenuViewController +{ + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) + { + let item = self.dataSource.item(at: indexPath) + item.isSelected = !item.isSelected + item.action(item) + + self.tableView.reloadData() + } +} diff --git a/Delta/Components/Popover Menu/PopoverMenuButton.swift b/Delta/Components/Popover Menu/PopoverMenuButton.swift new file mode 100644 index 0000000..f5bd940 --- /dev/null +++ b/Delta/Components/Popover Menu/PopoverMenuButton.swift @@ -0,0 +1,121 @@ +// +// PopoverMenuButton.swift +// Delta +// +// Created by Riley Testut on 9/2/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import UIKit + +extension UINavigationBar +{ + fileprivate var defaultTitleTextAttributes: [String: Any]? { + if let textAttributes = self._defaultTitleTextAttributes + { + return textAttributes + } + + // Make "copy" of self. + let navigationBar = UINavigationBar(frame: .zero) + navigationBar.barStyle = self.barStyle + + // Set item with title so we can retrieve default text attributes. + let navigationItem = UINavigationItem(title: "Testut") + navigationBar.items = [navigationItem] + navigationBar.isHidden = true + + // Must be added to window hierarchy for it to create title UILabel. + self.addSubview(navigationBar) + defer { navigationBar.removeFromSuperview() } + + navigationBar.layoutIfNeeded() + + let textAttributes = navigationBar._defaultTitleTextAttributes + return textAttributes + } + + fileprivate var _defaultTitleTextAttributes: [String: Any]? { + guard self.titleTextAttributes == nil else { return self.titleTextAttributes } + + guard + let contentView = self.subviews.first(where: { NSStringFromClass(type(of: $0)).contains("ContentView") || NSStringFromClass(type(of: $0)).contains("ItemView") }), + let titleLabel = contentView.subviews.first(where: { $0 is UILabel }) as? UILabel + else { return nil } + + let textAttributes = titleLabel.attributedText?.attributes(at: 0, effectiveRange: nil) + return textAttributes + } +} + +class PopoverMenuButton: UIControl +{ + var title: String { + get { return self.textLabel.text ?? "" } + set { + self.textLabel.text = newValue + self.updateTextAttributes() + self.invalidateIntrinsicContentSize() + } + } + + fileprivate let textLabel: UILabel + fileprivate let arrowLabel: UILabel + fileprivate let stackView: UIStackView + + fileprivate var parentNavigationBar: UINavigationBar? { + guard let navigationController = self.parentViewController as? UINavigationController ?? self.parentViewController?.navigationController else { return nil } + guard self.isDescendant(of: navigationController.navigationBar) else { return nil } + + return navigationController.navigationBar + } + + override var intrinsicContentSize: CGSize { + return self.stackView.systemLayoutSizeFitting(UILayoutFittingCompressedSize) + } + + init() + { + self.textLabel = UILabel() + self.textLabel.textColor = .black + + self.arrowLabel = UILabel() + self.arrowLabel.text = "▾" + self.arrowLabel.textColor = .black + + self.stackView = UIStackView(arrangedSubviews: [self.textLabel, self.arrowLabel]) + self.stackView.axis = .horizontal + self.stackView.distribution = .fillProportionally + self.stackView.alignment = .center + self.stackView.spacing = 4.0 + self.stackView.isUserInteractionEnabled = false + + let intrinsicContentSize = self.stackView.systemLayoutSizeFitting(UILayoutFittingCompressedSize) + super.init(frame: CGRect(origin: .zero, size: intrinsicContentSize)) + + self.addSubview(self.stackView, pinningEdgesWith: .zero) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func didMoveToSuperview() + { + self.updateTextAttributes() + } +} + +private extension PopoverMenuButton +{ + func updateTextAttributes() + { + guard let parentNavigationBar = self.parentNavigationBar else { return } + guard let textAttributes = parentNavigationBar.defaultTitleTextAttributes else { return } + + for label in [self.textLabel, self.arrowLabel] + { + label.attributedText = NSAttributedString(string: label.text ?? "", attributes: textAttributes) + } + } +} diff --git a/Delta/Components/Popover Menu/PopoverMenuController.swift b/Delta/Components/Popover Menu/PopoverMenuController.swift new file mode 100644 index 0000000..d90478e --- /dev/null +++ b/Delta/Components/Popover Menu/PopoverMenuController.swift @@ -0,0 +1,102 @@ +// +// PopoverMenuController.swift +// Delta +// +// Created by Riley Testut on 9/5/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import UIKit + +private var popoverMenuControllerKey: UInt8 = 0 + +extension UINavigationItem +{ + var popoverMenuController: PopoverMenuController? { + get { return objc_getAssociatedObject(self, &popoverMenuControllerKey) as? PopoverMenuController } + set { + self.titleView = newValue?.popoverMenuButton + objc_setAssociatedObject(self, &popoverMenuControllerKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} + +class PopoverMenuController: NSObject +{ + let popoverViewController: UIViewController + + let popoverMenuButton: PopoverMenuButton + + var isActive: Bool = false { + willSet { + guard newValue != self.isActive else { return } + + if newValue + { + self.presentPopoverViewController() + } + else + { + self.dismissPopoverViewController() + } + } + } + + init(popoverViewController: UIViewController) + { + self.popoverViewController = popoverViewController + + self.popoverMenuButton = PopoverMenuButton() + + super.init() + + self.popoverMenuButton.addTarget(self, action: #selector(PopoverMenuController.pressedPopoverMenuButton(_:)), for: .touchUpInside) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private extension PopoverMenuController +{ + @objc func pressedPopoverMenuButton(_ button: PopoverMenuButton) + { + self.isActive = !self.isActive + } + + func presentPopoverViewController() + { + guard !self.isActive else { return } + + guard let presentingViewController = self.popoverMenuButton.parentViewController else { return } + + self.popoverViewController.modalPresentationStyle = .popover + self.popoverViewController.popoverPresentationController?.delegate = self + self.popoverViewController.popoverPresentationController?.sourceView = self.popoverMenuButton.superview + self.popoverViewController.popoverPresentationController?.sourceRect = self.popoverMenuButton.frame + + presentingViewController.present(self.popoverViewController, animated: true, completion: nil) + } + + func dismissPopoverViewController() + { + guard self.isActive else { return } + + self.popoverViewController.dismiss(animated: true, completion: nil) + } +} + +extension PopoverMenuController: UIPopoverPresentationControllerDelegate +{ + func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle + { + // Force popover presentation, regardless of trait collection. + return .none + } + + func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) + { + self.isActive = false + } +} diff --git a/Delta/Components/Popover Menu/PopoverMenuViewController.swift b/Delta/Components/Popover Menu/PopoverMenuViewController.swift new file mode 100644 index 0000000..78c8ae8 --- /dev/null +++ b/Delta/Components/Popover Menu/PopoverMenuViewController.swift @@ -0,0 +1,68 @@ +// +// PopoverMenuViewController.swift +// Delta +// +// Created by Riley Testut on 9/2/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import UIKit + +import Roxas + +class ListMenuViewController: UITableViewController +{ + var items: [MenuItem] { + get { return self.dataSource.items } + set { self.dataSource.items = newValue; } + } + + fileprivate let dataSource = RSTArrayTableViewDataSource(items: []) + + override var preferredContentSize: CGSize { + get { + let navigationBarHeight = self.navigationController?.navigationBar.bounds.height ?? 0.0 + return CGSize(width: 0, height: (self.tableView.rowHeight * CGFloat(self.items.count)) + navigationBarHeight) + } + set {} + } + + init() + { + super.init(style: .plain) + + self.dataSource.cellConfigurationHandler = { (cell, item, indexPath) in + cell.textLabel?.text = item.text + cell.accessoryType = item.isSelected ? .checkmark : .none + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() + { + super.viewDidLoad() + + self.tableView.dataSource = self.dataSource + self.tableView.rowHeight = 44 + self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: RSTCellContentGenericCellIdentifier) + } +} + +extension ListMenuViewController +{ + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) + { + self.items.forEach { $0.isSelected = false } + + let item = self.dataSource.item(at: indexPath) + item.isSelected = true + item.action(item) + + self.tableView.reloadData() + + self.dismiss(animated: true, completion: nil) + } +} diff --git a/Delta/Database/Model/Human/ControllerSkin.swift b/Delta/Database/Model/Human/ControllerSkin.swift index 48ea7e0..7b73368 100644 --- a/Delta/Database/Model/Human/ControllerSkin.swift +++ b/Delta/Database/Model/Human/ControllerSkin.swift @@ -88,9 +88,9 @@ extension ControllerSkin: ControllerSkinProtocol return self.controllerSkin?.image(for: traits, preferredSize: preferredSize) } - public func inputs(for traits: DeltaCore.ControllerSkin.Traits, point: CGPoint) -> [Input]? + public func inputs(for traits: DeltaCore.ControllerSkin.Traits, at point: CGPoint) -> [Input]? { - return self.controllerSkin?.inputs(for: traits, point: point) + return self.controllerSkin?.inputs(for: traits, at: point) } public func items(for traits: DeltaCore.ControllerSkin.Traits) -> [DeltaCore.ControllerSkin.Item]? diff --git a/Delta/Emulation/ActionInput.swift b/Delta/Emulation/ActionInput.swift new file mode 100644 index 0000000..1f6db4a --- /dev/null +++ b/Delta/Emulation/ActionInput.swift @@ -0,0 +1,28 @@ +// +// ActionInput.swift +// Delta +// +// Created by Riley Testut on 8/28/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import DeltaCore + +public extension GameControllerInputType +{ + static let action = GameControllerInputType("com.rileytestut.Delta.input.action") +} + +enum ActionInput: String +{ + case saveState + case loadState + case fastForward +} + +extension ActionInput: Input +{ + var type: InputType { + return .controller(.action) + } +} diff --git a/Delta/Emulation/GameViewController.swift b/Delta/Emulation/GameViewController.swift index 1b3103e..21f9449 100644 --- a/Delta/Emulation/GameViewController.swift +++ b/Delta/Emulation/GameViewController.swift @@ -29,6 +29,22 @@ private extension GameViewController self.gameType = gameType } } + + struct SustainInputsMapping: GameControllerInputMappingProtocol + { + let gameControllerInputType: GameControllerInputType + let previousInputMapping: GameControllerInputMappingProtocol? + + func input(forControllerInput controllerInput: Input) -> Input? + { + if let mappedInput = self.previousInputMapping?.input(forControllerInput: controllerInput), mappedInput == StandardGameControllerInput.menu + { + return mappedInput + } + + return controllerInput + } + } } class GameViewController: DeltaCore.GameViewController @@ -79,10 +95,8 @@ class GameViewController: DeltaCore.GameViewController fileprivate var context = CIContext(options: [kCIContextWorkingColorSpace: NSNull()]) // Sustain Buttons - fileprivate var updateSemaphores = Set() - fileprivate var sustainedInputs = [ObjectIdentifier: [Input]]() - fileprivate var reactivateSustainedInputsQueue: OperationQueue - fileprivate var selectingSustainedButtons = false + fileprivate var isSelectingSustainedButtons = false + fileprivate var sustainInputsMapping: SustainInputsMapping? fileprivate var sustainButtonsContentView: UIView! fileprivate var sustainButtonsBlurView: UIVisualEffectView! @@ -90,9 +104,6 @@ class GameViewController: DeltaCore.GameViewController required init() { - self.reactivateSustainedInputsQueue = OperationQueue() - self.reactivateSustainedInputsQueue.maxConcurrentOperationCount = 1 - super.init() self.initialize() @@ -100,9 +111,6 @@ class GameViewController: DeltaCore.GameViewController required init?(coder aDecoder: NSCoder) { - self.reactivateSustainedInputsQueue = OperationQueue() - self.reactivateSustainedInputsQueue.maxConcurrentOperationCount = 1 - super.init(coder: aDecoder) self.initialize() @@ -112,8 +120,8 @@ class GameViewController: DeltaCore.GameViewController { self.delegate = self - NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalControllerDidConnect, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalControllerDidDisconnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalGameControllerDidConnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalGameControllerDidDisconnect, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didEnterBackground(with:)), name: .UIApplicationDidEnterBackground, object: UIApplication.shared) NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.settingsDidChange(with:)), name: .settingsDidChange, object: nil) } @@ -128,18 +136,13 @@ class GameViewController: DeltaCore.GameViewController { super.gameController(gameController, didActivate: input) - guard (input as? ControllerInput) != .menu else { return } + guard self.isSelectingSustainedButtons else { return } - if self.selectingSustainedButtons + guard let pausingGameController = self.pausingGameController, gameController == pausingGameController else { return } + + if input != StandardGameControllerInput.menu { - self.addSustainedInput(input, for: gameController) - } - else if let sustainedInputs = self.sustainedInputs[ObjectIdentifier(gameController)], sustainedInputs.contains(where: { $0.isEqual(input) }) - { - // Perform on next run loop - DispatchQueue.main.async { - self.reactivateSustainedInput(input, for: gameController) - } + gameController.sustain(input) } } } @@ -243,22 +246,28 @@ extension GameViewController pauseViewController.saveStatesViewControllerDelegate = self pauseViewController.cheatsViewControllerDelegate = self - pauseViewController.fastForwardItem?.selected = (self.emulatorCore?.rate != self.emulatorCore?.deltaCore.supportedRates.lowerBound) + pauseViewController.fastForwardItem?.isSelected = (self.emulatorCore?.rate != self.emulatorCore?.deltaCore.supportedRates.lowerBound) pauseViewController.fastForwardItem?.action = { [unowned self] item in guard let emulatorCore = self.emulatorCore else { return } - emulatorCore.rate = item.selected ? emulatorCore.deltaCore.supportedRates.upperBound : emulatorCore.deltaCore.supportedRates.lowerBound + emulatorCore.rate = item.isSelected ? emulatorCore.deltaCore.supportedRates.upperBound : emulatorCore.deltaCore.supportedRates.lowerBound } - pauseViewController.sustainButtonsItem?.selected = (self.sustainedInputs[ObjectIdentifier(gameController)]?.count ?? 0) > 0 + pauseViewController.sustainButtonsItem?.isSelected = gameController.sustainedInputs.count > 0 pauseViewController.sustainButtonsItem?.action = { [unowned self, unowned pauseViewController] item in - self.resetSustainedInputs(for: gameController) + for input in gameController.sustainedInputs + { + gameController.unsustain(input) + } - if item.selected + if item.isSelected { self.showSustainButtonView() pauseViewController.dismiss() } + + // Re-set gameController as pausingGameController. + self.pausingGameController = gameController } self.pauseViewController = pauseViewController @@ -346,11 +355,7 @@ private extension GameViewController { @objc func updateControllers() { - var controllers = [GameController]() - controllers.append(self.controllerView) - - // We need to map each item as a GameControllerProtocol due to a Swift bug - controllers.append(contentsOf: ExternalControllerManager.shared.connectedControllers.map { $0 as GameController }) + let controllers = [self.controllerView as GameController] + ExternalGameControllerManager.shared.connectedControllers if let index = Settings.localControllerPlayerIndex { @@ -590,17 +595,6 @@ extension GameViewController: SaveStatesViewControllerDelegate print(error) } - // Reactivate sustained inputs - for gameController in self.emulatorCore?.gameControllers ?? [] - { - guard let sustainedInputs = self.sustainedInputs[ObjectIdentifier(gameController)] else { continue } - - for input in sustainedInputs - { - self.reactivateSustainedInput(input, for: gameController) - } - } - self.pauseViewController?.dismiss() } } @@ -625,7 +619,12 @@ private extension GameViewController { func showSustainButtonView() { - self.selectingSustainedButtons = true + guard let gameController = self.pausingGameController else { return } + + self.isSelectingSustainedButtons = true + + self.sustainInputsMapping = SustainInputsMapping(gameControllerInputType: gameController.inputType, previousInputMapping: gameController.inputMapping) + gameController.inputMapping = self.sustainInputsMapping let blurEffect = self.sustainButtonsBlurView.effect self.sustainButtonsBlurView.effect = nil @@ -640,7 +639,18 @@ private extension GameViewController func hideSustainButtonView() { - self.selectingSustainedButtons = false + guard let gameController = self.pausingGameController else { return } + + self.isSelectingSustainedButtons = false + + gameController.inputMapping = self.sustainInputsMapping?.previousInputMapping + self.sustainInputsMapping = nil + + // Reactivate all sustained inputs, since they will now be mapped to game inputs. + for input in gameController.sustainedInputs + { + gameController.activate(input) + } let blurEffect = self.sustainButtonsBlurView.effect @@ -652,96 +662,6 @@ private extension GameViewController self.sustainButtonsBlurView.effect = blurEffect } } - - func resetSustainedInputs(for gameController: GameController) - { - if let previousInputs = self.sustainedInputs[ObjectIdentifier(gameController)] - { - let receivers = gameController.receivers - receivers.forEach { gameController.removeReceiver($0) } - - // Activate previousInputs without notifying anyone so we can then deactivate them - // We do this because deactivating an already deactivated input has no effect - previousInputs.forEach { gameController.activate($0) } - - receivers.forEach { gameController.addReceiver($0) } - - // Deactivate previously sustained inputs - previousInputs.forEach { gameController.deactivate($0) } - } - - self.sustainedInputs[ObjectIdentifier(gameController)] = [] - } - - func addSustainedInput(_ input: Input, for gameController: GameController) - { - var inputs = self.sustainedInputs[ObjectIdentifier(gameController)] ?? [] - - guard !inputs.contains(where: { $0.isEqual(input) }) else { return } - - inputs.append(input) - self.sustainedInputs[ObjectIdentifier(gameController)] = inputs - - let receivers = gameController.receivers - receivers.forEach { gameController.removeReceiver($0) } - - // Causes input to be considered deactivated, so gameController won't send a subsequent message to observers when user actually deactivates - // However, at this point the core still thinks it is activated, and is temporarily not a receiver, thus sustaining it - gameController.deactivate(input) - - receivers.forEach { gameController.addReceiver($0) } - } - - func reactivateSustainedInput(_ input: Input, for gameController: GameController) - { - // These MUST be performed serially, or else Bad Things Happen™ if multiple inputs are reactivated at once - self.reactivateSustainedInputsQueue.addOperation { - - // The manual activations/deactivations here are hidden implementation details, so we won't notify ourselves about them - gameController.removeReceiver(self) - - // Must deactivate first so core recognizes a secondary activation - gameController.deactivate(input) - - let dispatchQueue = DispatchQueue(label: "com.rileytestut.Delta.sustainButtonsQueue") - dispatchQueue.async { - - let semaphore = DispatchSemaphore(value: 0) - self.updateSemaphores.insert(semaphore) - - // To ensure the emulator core recognizes us activating the input again, we need to wait at least two frames - // Unfortunately we cannot init DispatchSemaphore with value less than 0 - // To compensate, we simply wait twice; once the first wait returns, we wait again - semaphore.wait() - semaphore.wait() - - // These MUST be performed serially, or else Bad Things Happen™ if multiple inputs are reactivated at once - self.reactivateSustainedInputsQueue.addOperation { - - self.updateSemaphores.remove(semaphore) - - // Ensure we still are not a receiver (to prevent rare race conditions) - gameController.removeReceiver(self) - - gameController.activate(input) - - let receivers = gameController.receivers - receivers.forEach { gameController.removeReceiver($0) } - - // Causes input to be considered deactivated, so gameController won't send a subsequent message to observers when user actually deactivates - // However, at this point the core still thinks it is activated, and is temporarily not a receiver, thus sustaining it - gameController.deactivate(input) - - receivers.forEach { gameController.addReceiver($0) } - } - - // More Bad Things Happen™ if we add self as observer before ALL reactivations have occurred (notable, infinite loops) - self.reactivateSustainedInputsQueue.waitUntilAllOperationsAreFinished() - - gameController.addReceiver(self) - } - } - } } //MARK: - GameViewControllerDelegate - @@ -750,12 +670,17 @@ extension GameViewController: GameViewControllerDelegate { func gameViewController(_ gameViewController: DeltaCore.GameViewController, handleMenuInputFrom gameController: GameController) { - if self.selectingSustainedButtons + if let pausingGameController = self.pausingGameController + { + guard pausingGameController == gameController else { return } + } + + if self.isSelectingSustainedButtons { self.hideSustainButtonView() } - if let pauseViewController = self.pauseViewController, !self.selectingSustainedButtons + if let pauseViewController = self.pauseViewController, !self.isSelectingSustainedButtons { pauseViewController.dismiss() } @@ -768,15 +693,7 @@ extension GameViewController: GameViewControllerDelegate func gameViewControllerShouldResumeEmulation(_ gameViewController: DeltaCore.GameViewController) -> Bool { - return (self.presentedViewController == nil || self.presentedViewController?.isDisappearing == true) && !self.selectingSustainedButtons && self.view.window != nil - } - - func gameViewControllerDidUpdate(_ gameViewController: DeltaCore.GameViewController) - { - for semaphore in self.updateSemaphores - { - semaphore.signal() - } + return (self.presentedViewController == nil || self.presentedViewController?.isDisappearing == true) && !self.isSelectingSustainedButtons && self.view.window != nil } } diff --git a/Delta/Extensions/Input+Display.swift b/Delta/Extensions/Input+Display.swift new file mode 100644 index 0000000..ac80b19 --- /dev/null +++ b/Delta/Extensions/Input+Display.swift @@ -0,0 +1,112 @@ +// +// Input+Display.swift +// Delta +// +// Created by Riley Testut on 8/15/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import DeltaCore + +extension Input +{ + // With the default GameControllerInputMapping files, multiple controller inputs may map to the same game input. + // This is because each controller input maps to a unique standard input, but then multiple standard inputs may map to same game input. + // To ensure we only show the most "important" controller input for a game input, we define general "display priorities" for each input. + // + // For example, MFiGameController.down and MFiGameController.leftThumbstickDown both map to a "down" game input. + // However, .down has a higher priority than .leftThumbstickDown, so we show .down instead of .leftThumbstickDown. + var displayPriority: Int { + switch self.type + { + case .game: break + case .controller(.standard): break + case .controller(.mfi): + let input = MFiGameController.Input(input: self)! + switch input + { + case .leftThumbstickUp: return 750 + case .leftThumbstickDown: return 750 + case .leftThumbstickLeft: return 750 + case .leftThumbstickRight: return 750 + case .leftShoulder: return 750 + case .leftTrigger: return 500 + case .rightShoulder: return 750 + case .rightTrigger: return 500 + default: break + } + + default: break + } + + return 1000 + } + + var localizedName: String { + switch self.type + { + case .game: break + case .controller(.standard): + let input = StandardGameControllerInput(input: self)! + switch input + { + case .menu: return NSLocalizedString("Menu", comment: "") + case .up: return NSLocalizedString("Up", comment: "") + case .down: return NSLocalizedString("Down", comment: "") + case .left: return NSLocalizedString("Left", comment: "") + case .right: return NSLocalizedString("Right", comment: "") + case .leftThumbstickUp: return NSLocalizedString("L🕹↑", comment: "") + case .leftThumbstickDown: return NSLocalizedString("L🕹↓", comment: "") + case .leftThumbstickLeft: return NSLocalizedString("L🕹←", comment: "") + case .leftThumbstickRight: return NSLocalizedString("L🕹→", comment: "") + case .rightThumbstickUp: return NSLocalizedString("R🕹↑", comment: "") + case .rightThumbstickDown: return NSLocalizedString("R🕹↓", comment: "") + case .rightThumbstickLeft: return NSLocalizedString("R🕹←", comment: "") + case .rightThumbstickRight: return NSLocalizedString("R🕹→", comment: "") + case .a: return NSLocalizedString("A", comment: "") + case .b: return NSLocalizedString("B", comment: "") + case .x: return NSLocalizedString("X", comment: "") + case .y: return NSLocalizedString("Y", comment: "") + case .start: return NSLocalizedString("Start", comment: "Start button") + case .select: return NSLocalizedString("Select", comment: "Select button") + case .l1: return NSLocalizedString("L1", comment: "") + case .l2: return NSLocalizedString("L2", comment: "") + case .l3: return NSLocalizedString("L3", comment: "") + case .r1: return NSLocalizedString("R1", comment: "") + case .r2: return NSLocalizedString("R2", comment: "") + case .r3: return NSLocalizedString("R3", comment: "") + } + + case .controller(.mfi): + let input = MFiGameController.Input(input: self)! + switch input + { + case .menu: return NSLocalizedString("Menu", comment: "") + case .up: return NSLocalizedString("Up", comment: "") + case .down: return NSLocalizedString("Down", comment: "") + case .left: return NSLocalizedString("Left", comment: "") + case .right: return NSLocalizedString("Right", comment: "") + case .leftThumbstickUp: return NSLocalizedString("L🕹↑", comment: "") + case .leftThumbstickDown: return NSLocalizedString("L🕹↓", comment: "") + case .leftThumbstickLeft: return NSLocalizedString("L🕹←", comment: "") + case .leftThumbstickRight: return NSLocalizedString("L🕹→", comment: "") + case .rightThumbstickUp: return NSLocalizedString("R🕹↑", comment: "") + case .rightThumbstickDown: return NSLocalizedString("R🕹↓", comment: "") + case .rightThumbstickLeft: return NSLocalizedString("R🕹←", comment: "") + case .rightThumbstickRight: return NSLocalizedString("R🕹→", comment: "") + case .a: return NSLocalizedString("A", comment: "") + case .b: return NSLocalizedString("B", comment: "") + case .x: return NSLocalizedString("X", comment: "") + case .y: return NSLocalizedString("Y", comment: "") + case .leftShoulder: return NSLocalizedString("L1", comment: "") + case .leftTrigger: return NSLocalizedString("L2", comment: "") + case .rightShoulder: return NSLocalizedString("R1", comment: "") + case .rightTrigger: return NSLocalizedString("R2", comment: "") + } + + default: break + } + + return "" + } +} diff --git a/Delta/Extensions/UIView+ParentViewController.swift b/Delta/Extensions/UIView+ParentViewController.swift new file mode 100644 index 0000000..2213199 --- /dev/null +++ b/Delta/Extensions/UIView+ParentViewController.swift @@ -0,0 +1,28 @@ +// +// UIView+ParentViewController.swift +// Delta +// +// Created by Riley Testut on 9/3/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import UIKit + +extension UIView +{ + var parentViewController: UIViewController? { + var nextResponder = self.next + + while nextResponder != nil + { + if let parentViewController = nextResponder as? UIViewController + { + return parentViewController + } + + nextResponder = nextResponder?.next + } + + return nil + } +} diff --git a/Delta/Pause Menu/PauseMenuViewController.swift b/Delta/Pause Menu/GridMenuViewController.swift similarity index 53% rename from Delta/Pause Menu/PauseMenuViewController.swift rename to Delta/Pause Menu/GridMenuViewController.swift index a887cb4..8552552 100644 --- a/Delta/Pause Menu/PauseMenuViewController.swift +++ b/Delta/Pause Menu/GridMenuViewController.swift @@ -1,5 +1,5 @@ // -// PauseMenuViewController.swift +// GridMenuViewController.swift // Delta // // Created by Riley Testut on 12/21/15. @@ -9,39 +9,57 @@ import UIKit import Roxas -class PauseMenuViewController: UICollectionViewController +class GridMenuViewController: UICollectionViewController { - var items = [PauseItem]() { - didSet - { - guard oldValue != self.items else { return } - - if self.items.count > 8 - { - fatalError("PauseViewController only supports up to 8 items (for my sanity when laying out on a landscape iPhone 4s") - } - - self.dataSource.items = self.items - } + var items: [MenuItem] { + get { return self.dataSource.items } + set { self.dataSource.items = newValue; self.updateItems() } } + var isVibrancyEnabled = true + override var preferredContentSize: CGSize { set { } get { return self.collectionView?.contentSize ?? CGSize.zero } } - fileprivate let dataSource = RSTArrayCollectionViewDataSource(items: []) + fileprivate let dataSource = RSTArrayCollectionViewDataSource(items: []) fileprivate var prototypeCell = GridCollectionViewCell() fileprivate var previousIndexPath: IndexPath? = nil + + fileprivate var registeredKVOObservers = Set() + + init() + { + let collectionViewLayout = GridCollectionViewLayout() + collectionViewLayout.itemSize = CGSize(width: 60, height: 80) + collectionViewLayout.minimumLineSpacing = 20 + collectionViewLayout.minimumInteritemSpacing = 10 + + super.init(collectionViewLayout: collectionViewLayout) + } + + required init?(coder aDecoder: NSCoder) + { + super.init(coder: aDecoder) + } + + deinit + { + // Crashes on iOS 10 if not explicitly invalidated. + self.registeredKVOObservers.forEach { $0.invalidate() } + } } -extension PauseMenuViewController +extension GridMenuViewController { override func viewDidLoad() { super.viewDidLoad() + self.collectionView?.register(GridCollectionViewCell.self, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) + self.dataSource.cellConfigurationHandler = { [unowned self] (cell, item, indexPath) in self.configure(cell as! GridCollectionViewCell, for: indexPath) } @@ -62,55 +80,66 @@ extension PauseMenuViewController if let indexPath = self.previousIndexPath { UIView.animate(withDuration: 0.2) { - self.toggleSelectedStateForPauseItemAtIndexPath(indexPath) + let item = self.items[indexPath.item] + item.isSelected = !item.isSelected } } } } -private extension PauseMenuViewController +private extension GridMenuViewController { func configure(_ cell: GridCollectionViewCell, for indexPath: IndexPath) { - let pauseItem = self.items[(indexPath as NSIndexPath).item] + let pauseItem = self.items[indexPath.item] cell.maximumImageSize = CGSize(width: 60, height: 60) cell.imageView.image = pauseItem.image cell.imageView.contentMode = .center cell.imageView.layer.borderWidth = 2 - cell.imageView.layer.borderColor = UIColor.white.cgColor + cell.imageView.layer.borderColor = self.view.tintColor.cgColor cell.imageView.layer.cornerRadius = 10 cell.textLabel.text = pauseItem.text - cell.textLabel.textColor = UIColor.white + cell.textLabel.textColor = self.view.tintColor - if pauseItem.selected + if pauseItem.isSelected { cell.imageView.tintColor = UIColor.black - cell.imageView.backgroundColor = UIColor.white + cell.imageView.backgroundColor = self.view.tintColor } else { - cell.imageView.tintColor = UIColor.white + cell.imageView.tintColor = self.view.tintColor cell.imageView.backgroundColor = UIColor.clear } - cell.isImageViewVibrancyEnabled = true - cell.isTextLabelVibrancyEnabled = true + cell.isImageViewVibrancyEnabled = self.isVibrancyEnabled + cell.isTextLabelVibrancyEnabled = self.isVibrancyEnabled } - func toggleSelectedStateForPauseItemAtIndexPath(_ indexPath: IndexPath) + func updateItems() { - let pauseItem = self.items[indexPath.item] - pauseItem.selected = !pauseItem.selected + self.registeredKVOObservers.removeAll() - let cell = self.collectionView!.cellForItem(at: indexPath) as! GridCollectionViewCell - self.configure(cell, for: indexPath) + for (index, item) in self.items.enumerated() + { + let observer = item.observe(\.isSelected, changeHandler: { [unowned self] (item, change) in + let indexPath = IndexPath(item: index, section: 0) + + if let cell = self.collectionView?.cellForItem(at: indexPath) as? GridCollectionViewCell + { + self.configure(cell, for: indexPath) + } + }) + + self.registeredKVOObservers.insert(observer) + } } } -extension PauseMenuViewController: UICollectionViewDelegateFlowLayout +extension GridMenuViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { @@ -121,26 +150,27 @@ extension PauseMenuViewController: UICollectionViewDelegateFlowLayout } } -extension PauseMenuViewController +extension GridMenuViewController { override func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) { - self.toggleSelectedStateForPauseItemAtIndexPath(indexPath) + let item = self.items[indexPath.item] + item.isSelected = !item.isSelected } override func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) { - self.toggleSelectedStateForPauseItemAtIndexPath(indexPath) + let item = self.items[indexPath.item] + item.isSelected = !item.isSelected } override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { self.previousIndexPath = indexPath - self.toggleSelectedStateForPauseItemAtIndexPath(indexPath) - - let pauseItem = self.items[indexPath.item] - pauseItem.action(pauseItem) + let item = self.items[indexPath.item] + item.isSelected = !item.isSelected + item.action(item) } } diff --git a/Delta/Pause Menu/MenuItem.swift b/Delta/Pause Menu/MenuItem.swift new file mode 100644 index 0000000..3335b9c --- /dev/null +++ b/Delta/Pause Menu/MenuItem.swift @@ -0,0 +1,35 @@ +// +// MenuItem.swift +// Delta +// +// Created by Riley Testut on 1/30/16. +// Copyright © 2016 Riley Testut. All rights reserved. +// + +import UIKit + +// Must be class for use with Objective-C generics :( +class MenuItem: NSObject +{ + var text: String + var image: UIImage? + var action: ((MenuItem) -> Void) + + @objc dynamic var isSelected = false + + init(text: String, image: UIImage?, action: @escaping ((MenuItem) -> Void)) + { + self.image = image + self.text = text + self.action = action + } +} + +extension MenuItem +{ + override func isEqual(_ object: Any?) -> Bool + { + guard let item = object as? MenuItem else { return false } + return item.image == self.image && item.text == self.text + } +} diff --git a/Delta/Pause Menu/PauseItem.swift b/Delta/Pause Menu/PauseItem.swift deleted file mode 100644 index e1c629b..0000000 --- a/Delta/Pause Menu/PauseItem.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// PauseItem.swift -// Delta -// -// Created by Riley Testut on 1/30/16. -// Copyright © 2016 Riley Testut. All rights reserved. -// - -import UIKit - -// Must be class for use with Objective-C generics :( -class PauseItem: Equatable -{ - var image: UIImage - var text: String - var action: ((PauseItem) -> Void) - - var selected = false - - init(image: UIImage, text: String, action: @escaping ((PauseItem) -> Void)) - { - self.image = image - self.text = text - self.action = action - } -} - -func ==(lhs: PauseItem, rhs: PauseItem) -> Bool -{ - return (lhs.image == rhs.image) && (lhs.text == rhs.text) -} diff --git a/Delta/Pause Menu/PauseViewController.swift b/Delta/Pause Menu/PauseViewController.swift index 10a4d02..9287e85 100644 --- a/Delta/Pause Menu/PauseViewController.swift +++ b/Delta/Pause Menu/PauseViewController.swift @@ -18,16 +18,16 @@ class PauseViewController: UIViewController, PauseInfoProviding } } - var pauseItems: [PauseItem] { + var pauseItems: [MenuItem] { return [self.saveStateItem, self.loadStateItem, self.cheatCodesItem, self.fastForwardItem, self.sustainButtonsItem].flatMap { $0 } } /// Pause Items - var saveStateItem: PauseItem? - var loadStateItem: PauseItem? - var cheatCodesItem: PauseItem? - var fastForwardItem: PauseItem? - var sustainButtonsItem: PauseItem? + var saveStateItem: MenuItem? + var loadStateItem: MenuItem? + var cheatCodesItem: MenuItem? + var fastForwardItem: MenuItem? + var sustainButtonsItem: MenuItem? /// PauseInfoProviding var pauseText: String? @@ -85,8 +85,8 @@ extension PauseViewController self.pauseNavigationController.navigationBar.tintColor = UIColor.deltaPurple self.pauseNavigationController.view.backgroundColor = UIColor.clear - let pauseMenuViewController = self.pauseNavigationController.topViewController as! PauseMenuViewController - pauseMenuViewController.items = self.pauseItems + let gridMenuViewController = self.pauseNavigationController.topViewController as! GridMenuViewController + gridMenuViewController.items = self.pauseItems case "saveStates": let saveStatesViewController = segue.destination as! SaveStatesViewController @@ -135,21 +135,21 @@ private extension PauseViewController guard self.emulatorCore != nil else { return } - self.saveStateItem = PauseItem(image: #imageLiteral(resourceName: "SaveSaveState"), text: NSLocalizedString("Save State", comment: ""), action: { [unowned self] _ in + self.saveStateItem = MenuItem(text: NSLocalizedString("Save State", comment: ""), image: #imageLiteral(resourceName: "SaveSaveState"), action: { [unowned self] _ in self.saveStatesViewControllerMode = .saving self.performSegue(withIdentifier: "saveStates", sender: self) }) - self.loadStateItem = PauseItem(image: #imageLiteral(resourceName: "LoadSaveState"), text: NSLocalizedString("Load State", comment: ""), action: { [unowned self] _ in + self.loadStateItem = MenuItem(text: NSLocalizedString("Load State", comment: ""), image: #imageLiteral(resourceName: "LoadSaveState"), action: { [unowned self] _ in self.saveStatesViewControllerMode = .loading self.performSegue(withIdentifier: "saveStates", sender: self) }) - self.cheatCodesItem = PauseItem(image: #imageLiteral(resourceName: "CheatCodes"), text: NSLocalizedString("Cheat Codes", comment: ""), action: { [unowned self] _ in + self.cheatCodesItem = MenuItem(text: NSLocalizedString("Cheat Codes", comment: ""), image: #imageLiteral(resourceName: "CheatCodes"), action: { [unowned self] _ in self.performSegue(withIdentifier: "cheats", sender: self) }) - self.fastForwardItem = PauseItem(image: #imageLiteral(resourceName: "FastForward"), text: NSLocalizedString("Fast Forward", comment: ""), action: { _ in }) - self.sustainButtonsItem = PauseItem(image: #imageLiteral(resourceName: "SustainButtons"), text: NSLocalizedString("Sustain Buttons", comment: ""), action: { _ in }) + self.fastForwardItem = MenuItem(text: NSLocalizedString("Fast Forward", comment: ""), image: #imageLiteral(resourceName: "FastForward"), action: { _ in }) + self.sustainButtonsItem = MenuItem(text: NSLocalizedString("Sustain Buttons", comment: ""), image: #imageLiteral(resourceName: "SustainButtons"), action: { _ in }) } } diff --git a/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift b/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift index bec5a67..6081cfd 100644 --- a/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift +++ b/Delta/Pause Menu/Segues/PauseStoryboardSegue.swift @@ -29,6 +29,9 @@ class PauseStoryboardSegue: UIStoryboardSegue self.destination.modalPresentationStyle = .custom self.destination.modalPresentationCapturesStatusBarAppearance = true + // Manually set tint color, since calling layoutIfNeeded will cause view to load, but with default system tint color. + self.destination.view.tintColor = .white + // We need to force layout of destinationViewController.view _before_ animateTransition(using:) // Otherwise, we'll get "Unable to simultaneously satisfy constraints" errors self.destination.view.frame = self.source.view.frame diff --git a/Delta/Settings/Controllers/ControllerInputsViewController.swift b/Delta/Settings/Controllers/ControllerInputsViewController.swift new file mode 100644 index 0000000..8edff0a --- /dev/null +++ b/Delta/Settings/Controllers/ControllerInputsViewController.swift @@ -0,0 +1,480 @@ +// +// ControllerInputsViewController.swift +// Delta +// +// Created by Riley Testut on 7/1/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import UIKit +import Roxas + +import DeltaCore + +import SMCalloutView + +class ControllerInputsViewController: UIViewController +{ + var gameController: GameController! { + didSet { + self.prepareGameController() + } + } + + var system: System = .snes { + didSet { + guard self.system != oldValue else { return } + self.updateSystem() + } + } + + fileprivate var inputMapping: GameControllerInputMapping! + fileprivate var previousInputMapping: GameControllerInputMappingProtocol? + + fileprivate let supportedActionInputs: [ActionInput] = [.saveState, .loadState, .fastForward] + + fileprivate var gameViewController: DeltaCore.GameViewController! + fileprivate var actionsMenuViewController: GridMenuViewController! + + fileprivate var calloutViews = [AnyInput: InputCalloutView]() + + fileprivate var activeCalloutView: InputCalloutView? + + @IBOutlet private var actionsMenuViewControllerHeightConstraint: NSLayoutConstraint! + @IBOutlet private var cancelTapGestureRecognizer: UITapGestureRecognizer! + + override func viewDidLoad() + { + super.viewDidLoad() + + self.gameViewController.controllerView.addReceiver(self) + + self.navigationController?.navigationBar.barStyle = .black + + NSLayoutConstraint.activate([self.gameViewController.gameView.centerYAnchor.constraint(equalTo: self.actionsMenuViewController.view.centerYAnchor)]) + + self.preparePopoverMenuController() + self.updateSystem() + } + + override func viewDidLayoutSubviews() + { + super.viewDidLayoutSubviews() + + if self.actionsMenuViewController.preferredContentSize.height > 0 + { + self.actionsMenuViewControllerHeightConstraint.constant = self.actionsMenuViewController.preferredContentSize.height + } + } + + override func viewDidAppear(_ animated: Bool) + { + super.viewDidAppear(animated) + + if self.calloutViews.isEmpty + { + self.prepareCallouts() + } + } +} + +extension ControllerInputsViewController +{ + override func prepare(for segue: UIStoryboardSegue, sender: Any?) + { + guard let identifier = segue.identifier else { return } + + switch identifier + { + case "embedGameViewController": self.gameViewController = segue.destination as! DeltaCore.GameViewController + case "embedActionsMenuViewController": + self.actionsMenuViewController = segue.destination as! GridMenuViewController + self.prepareActionsMenuViewController() + + case "cancelControllerControls": self.gameController.inputMapping = self.previousInputMapping + case "saveControllerControls": self.gameController.inputMapping = self.inputMapping + + default: break + } + } +} + +private extension ControllerInputsViewController +{ + func updateSystem() + { + guard self.isViewLoaded else { return } + + if let popoverMenuButton = self.navigationItem.popoverMenuController?.popoverMenuButton + { + popoverMenuButton.title = self.system.localizedShortName + popoverMenuButton.bounds.size = popoverMenuButton.intrinsicContentSize + + self.navigationController?.navigationBar.layoutIfNeeded() + } + + self.gameViewController.controllerView.controllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: self.system.gameType) + + if self.view.window != nil + { + self.calloutViews.forEach { $1.dismissCallout(animated: true) } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + self.calloutViews = [:] + self.prepareCallouts() + } + } + } + + func prepareGameController() + { + self.gameController.addReceiver(self) + + self.previousInputMapping = self.gameController.inputMapping + + self.inputMapping = self.gameController.inputMapping as? GameControllerInputMapping ?? GameControllerInputMapping(gameControllerInputType: self.gameController.inputType) + self.inputMapping.name = String.localizedStringWithFormat("Custom %@", self.gameController.name) + + self.gameController.inputMapping = nil + } + + func preparePopoverMenuController() + { + let listMenuViewController = ListMenuViewController() + listMenuViewController.title = NSLocalizedString("Game System", comment: "") + + let navigationController = UINavigationController(rootViewController: listMenuViewController) + + let popoverMenuController = PopoverMenuController(popoverViewController: navigationController) + self.navigationItem.popoverMenuController = popoverMenuController + + let items = System.supportedSystems.map { [unowned self, weak popoverMenuController, weak listMenuViewController] system -> MenuItem in + let item = MenuItem(text: system.localizedShortName, image: #imageLiteral(resourceName: "CheatCodes")) { [weak popoverMenuController, weak listMenuViewController] item in + listMenuViewController?.items.forEach { $0.isSelected = ($0 == item) } + popoverMenuController?.isActive = false + + self.system = system + } + item.isSelected = (system == self.system) + + return item + } + listMenuViewController.items = items + } + + func prepareActionsMenuViewController() + { + var items = [MenuItem]() + + for input in self.supportedActionInputs + { + let image: UIImage + let text: String + + switch input + { + case .saveState: + image = #imageLiteral(resourceName: "SaveSaveState") + text = NSLocalizedString("Save State", comment: "") + + case .loadState: + image = #imageLiteral(resourceName: "LoadSaveState") + text = NSLocalizedString("Load State", comment: "") + + case .fastForward: + image = #imageLiteral(resourceName: "FastForward") + text = NSLocalizedString("Fast Forward", comment: "") + } + + let item = MenuItem(text: text, image: image) { (item) in + guard let calloutView = self.calloutViews[AnyInput(input)] else { return } + self.toggle(calloutView) + } + + items.append(item) + } + + self.actionsMenuViewController.items = items + self.actionsMenuViewController.isVibrancyEnabled = false + } + + func prepareCallouts() + { + guard + let controllerView = self.gameViewController.controllerView, + let traits = controllerView.controllerSkinTraits, + let items = controllerView.controllerSkin?.items(for: traits), + let controllerViewInputMapping = controllerView.inputMapping + else { return } + + // Implicit assumption that all skins used for controller input mapping don't have multiple items with same input. + let mappedInputs = items.flatMap { $0.inputs.allInputs.flatMap(controllerViewInputMapping.input(forControllerInput:)) } + (self.supportedActionInputs as [Input]) + + // Create callout view for each on-screen input. + for input in mappedInputs + { + let calloutView = InputCalloutView() + calloutView.delegate = self + self.calloutViews[AnyInput(input)] = calloutView + } + + // Update callout views with controller inputs that map to callout views' associated controller skin inputs. + for input in self.inputMapping.supportedControllerInputs + { + let mappedInput = self.mappedInput(for: input) + + if let calloutView = self.calloutViews[mappedInput] + { + if let previousInput = calloutView.input + { + // Ensure the input we display has a higher priority. + calloutView.input = (input.displayPriority > previousInput.displayPriority) ? input : previousInput + } + else + { + calloutView.input = input + } + } + } + + // Present only callout views that are associated with a controller input. + for calloutView in self.calloutViews.values + { + if let presentationRect = self.presentationRect(for: calloutView), calloutView.input != nil + { + calloutView.presentCallout(from: presentationRect, in: self.view, constrainedTo: self.view, animated: true) + } + } + } +} + +private extension ControllerInputsViewController +{ + func updateActiveCalloutView(with controllerInput: Input?) + { + guard let activeCalloutView = self.activeCalloutView else { return } + + guard let input = self.calloutViews.first(where: { $0.value == activeCalloutView })?.key else { return } + + if let controllerInput = controllerInput + { + for (_, calloutView) in self.calloutViews + { + guard let calloutInput = calloutView.input else { continue } + + if calloutInput == controllerInput + { + // Hide callout views that previously displayed the controller input. + calloutView.input = nil + calloutView.dismissCallout(animated: true) + } + } + } + + for supportedInput in self.inputMapping.supportedControllerInputs + { + let mappedInput = self.mappedInput(for: supportedInput) + + if mappedInput == input + { + // Set all existing controller inputs that currently map to "input" to instead map to nil. + self.inputMapping.set(nil, forControllerInput: supportedInput) + } + } + + if let controllerInput = controllerInput + { + self.inputMapping.set(input, forControllerInput: controllerInput) + } + + activeCalloutView.input = controllerInput + + self.toggle(activeCalloutView) + } + + func toggle(_ calloutView: InputCalloutView) + { + if let activeCalloutView = self.activeCalloutView, activeCalloutView != calloutView + { + self.toggle(activeCalloutView) + } + + let menuItem: MenuItem? + + if let input = self.calloutViews.first(where: { $0.value == calloutView })?.key, let index = self.supportedActionInputs.index(where: { $0 == input }) + { + menuItem = self.actionsMenuViewController.items[index] + } + else + { + menuItem = nil + } + + switch calloutView.state + { + case .normal: + calloutView.state = .listening + menuItem?.isSelected = true + self.activeCalloutView = calloutView + + case .listening: + calloutView.state = .normal + menuItem?.isSelected = false + self.activeCalloutView = nil + } + + calloutView.dismissCallout(animated: true) + + if let presentationRect = self.presentationRect(for: calloutView) + { + if calloutView.state == .listening || calloutView.input != nil + { + calloutView.presentCallout(from: presentationRect, in: self.view, constrainedTo: self.view, animated: true) + } + } + } +} + +extension ControllerInputsViewController: UIGestureRecognizerDelegate +{ + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool + { + return self.activeCalloutView != nil + } + + @IBAction private func handleTapGesture(_ tapGestureRecognizer: UITapGestureRecognizer) + { + self.updateActiveCalloutView(with: nil) + } +} + +private extension ControllerInputsViewController +{ + func mappedInput(for input: Input) -> AnyInput + { + guard let mappedInput = self.inputMapping.input(forControllerInput: input) else { + fatalError("Mapped input for provided input does not exist.") + } + + if let standardInput = StandardGameControllerInput(input: mappedInput) + { + if let gameInput = standardInput.input(for: self.system.gameType) + { + return AnyInput(gameInput) + } + } + + return AnyInput(mappedInput) + } + + func presentationRect(for calloutView: InputCalloutView) -> CGRect? + { + guard let input = self.calloutViews.first(where: { $0.value == calloutView })?.key else { return nil } + + guard + let controllerView = self.gameViewController.controllerView, + let traits = controllerView.controllerSkinTraits, + let items = controllerView.controllerSkin?.items(for: traits) + else { return nil } + + if let item = items.first(where: { $0.inputs.allInputs.contains(where: { $0.stringValue == input.stringValue })}) + { + // Input is a controller skin input. + + let itemFrame: CGRect? + + switch item.inputs + { + case .standard: itemFrame = item.frame + case let .directional(up, down, left, right): + + switch input.stringValue + { + case up.stringValue: + itemFrame = CGRect(x: item.frame.minX + item.frame.width / 3, + y: item.frame.minY, + width: item.frame.width / 3, + height: item.frame.height / 3) + case down.stringValue: + itemFrame = CGRect(x: item.frame.minX + item.frame.width / 3, + y: item.frame.minY + (item.frame.height / 3) * 2, + width: item.frame.width / 3, + height: item.frame.height / 3) + + case left.stringValue: + itemFrame = CGRect(x: item.frame.minX, + y: item.frame.minY + (item.frame.height / 3), + width: item.frame.width / 3, + height: item.frame.height / 3) + + case right.stringValue: + itemFrame = CGRect(x: item.frame.minX + (item.frame.width / 3) * 2, + y: item.frame.minY + (item.frame.height / 3), + width: item.frame.width / 3, + height: item.frame.height / 3) + + default: itemFrame = nil + } + } + + if let itemFrame = itemFrame + { + var presentationFrame = itemFrame.applying(CGAffineTransform(scaleX: controllerView.bounds.width, y: controllerView.bounds.height)) + presentationFrame = self.view.convert(presentationFrame, from: controllerView) + + return presentationFrame + } + } + else if let index = self.supportedActionInputs.index(where: { $0 == input }) + { + // Input is an ActionInput. + + let indexPath = IndexPath(item: index, section: 0) + + if let attributes = self.actionsMenuViewController.collectionViewLayout.layoutAttributesForItem(at: indexPath) + { + let presentationFrame = self.view.convert(attributes.frame, from: self.actionsMenuViewController.view) + return presentationFrame + } + } + else + { + // Input is not an on-screen input. + } + + return nil + } +} + +extension ControllerInputsViewController: GameControllerReceiver +{ + func gameController(_ gameController: GameController, didActivate controllerInput: DeltaCore.Input) + { + switch gameController + { + case self.gameViewController.controllerView: + if let calloutView = self.calloutViews[AnyInput(controllerInput)] + { + self.toggle(calloutView) + } + + case self.gameController: self.updateActiveCalloutView(with: controllerInput) + + default: break + } + } + + func gameController(_ gameController: GameController, didDeactivate input: DeltaCore.Input) + { + } +} + +extension ControllerInputsViewController: SMCalloutViewDelegate +{ + func calloutViewClicked(_ calloutView: SMCalloutView) + { + guard let calloutView = calloutView as? InputCalloutView else { return } + + self.toggle(calloutView) + } +} diff --git a/Delta/Settings/Controllers/ControllersSettingsViewController.swift b/Delta/Settings/Controllers/ControllersSettingsViewController.swift index f5499ae..5123f77 100644 --- a/Delta/Settings/Controllers/ControllersSettingsViewController.swift +++ b/Delta/Settings/Controllers/ControllersSettingsViewController.swift @@ -9,37 +9,52 @@ import UIKit import DeltaCore -private enum ControllersSettingsSection: Int +import Roxas + +extension ControllersSettingsViewController { - case none - case localDevice - case externalControllers + fileprivate enum Section: Int + { + case none + case localDevice + case externalControllers + case customizeControls + } } -private class LocalDeviceController: ExternalController + +private class LocalDeviceController: NSObject, GameController { - override var name: String { + var name: String { return UIDevice.current.name } + + var playerIndex: Int? { + set { Settings.localControllerPlayerIndex = newValue } + get { return Settings.localControllerPlayerIndex } + } + + let inputType: GameControllerInputType = .standard + + var inputMapping: GameControllerInputMappingProtocol? } class ControllersSettingsViewController: UITableViewController { - var playerIndex: Int? { - didSet - { - if let playerIndex = self.playerIndex - { - self.title = NSLocalizedString("Player \(playerIndex + 1)", comment: "") - } - else - { - self.title = NSLocalizedString("Controllers", comment: "") - } + var playerIndex: Int! { + didSet { + self.title = NSLocalizedString("Player \(self.playerIndex + 1)", comment: "") } } - fileprivate var connectedControllers = ExternalControllerManager.shared.connectedControllers.sorted(by: { $0.playerIndex ?? NSIntegerMax < $1.playerIndex ?? NSIntegerMax }) + fileprivate var gameController: GameController? { + didSet { + oldValue?.playerIndex = nil + self.gameController?.playerIndex = self.playerIndex + } + } + + fileprivate var connectedControllers = ExternalGameControllerManager.shared.connectedControllers.sorted(by: { $0.playerIndex ?? NSIntegerMax < $1.playerIndex ?? NSIntegerMax }) fileprivate lazy var localDeviceController: LocalDeviceController = { let device = LocalDeviceController() @@ -52,146 +67,76 @@ class ControllersSettingsViewController: UITableViewController { super.init(coder: aDecoder) - NotificationCenter.default.addObserver(self, selector: #selector(ControllersSettingsViewController.externalControllerDidConnect(_:)), name: .externalControllerDidConnect, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(ControllersSettingsViewController.externalControllerDidDisconnect(_:)), name: .externalControllerDidDisconnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(ControllersSettingsViewController.externalGameControllerDidConnect(_:)), name: .externalGameControllerDidConnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(ControllersSettingsViewController.externalGameControllerDidDisconnect(_:)), name: .externalGameControllerDidDisconnect, object: nil) } override func viewDidLoad() { super.viewDidLoad() - } - - //MARK: - Storyboards - - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) - { - guard let indexPath = self.tableView.indexPathForSelectedRow else { return } - var controllers = self.connectedControllers - controllers.append(self.localDeviceController) - - // Reset previous controller - if let playerIndex = self.playerIndex, let index = controllers.index(where: { $0.playerIndex == playerIndex }) + let gameControllers = [self.localDeviceController as GameController] + self.connectedControllers + for gameController in gameControllers { - let controller = controllers[index] - controller.playerIndex = nil - } - - switch ControllersSettingsSection(rawValue: (indexPath as NSIndexPath).section)! - { - case .none: break - case .localDevice: self.localDeviceController.playerIndex = self.playerIndex - case .externalControllers: - let controller = self.connectedControllers[(indexPath as NSIndexPath).row] - controller.playerIndex = self.playerIndex - } - - // Updates in case we reset it above, as well as if we updated in the switch statement - Settings.localControllerPlayerIndex = self.localDeviceController.playerIndex - } -} - -private extension ControllersSettingsViewController -{ - dynamic func externalControllerDidConnect(_ notification: Notification) - { - guard let controller = notification.object as? ExternalController else { return } - - if let playerIndex = controller.playerIndex - { - self.connectedControllers.insert(controller, at: playerIndex) - } - else - { - self.connectedControllers.append(controller) - } - - if let index = self.connectedControllers.index(of: controller) - { - if self.connectedControllers.count == 1 + if gameController.playerIndex == self.playerIndex { - self.tableView.insertSections(IndexSet(integer: ControllersSettingsSection.externalControllers.rawValue), with: .fade) + self.gameController = gameController + break } - else - { - self.tableView.insertRows(at: [IndexPath(row: index, section: ControllersSettingsSection.externalControllers.rawValue)], with: .automatic) - } - } - } - - dynamic func externalControllerDidDisconnect(_ notification: Notification) - { - guard let controller = notification.object as? ExternalController else { return } - - if let index = self.connectedControllers.index(of: controller) - { - self.connectedControllers.remove(at: index) - - if self.connectedControllers.count == 0 - { - self.tableView.deleteSections(IndexSet(integer: ControllersSettingsSection.externalControllers.rawValue), with: .fade) - } - else - { - self.tableView.deleteRows(at: [IndexPath(row: index, section: ControllersSettingsSection.externalControllers.rawValue)], with: .automatic) - } - } - - if controller.playerIndex == self.playerIndex - { - self.tableView.reloadSections(IndexSet(integer: ControllersSettingsSection.none.rawValue), with: .none) } } } extension ControllersSettingsViewController { - override func numberOfSections(in tableView: UITableView) -> Int + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - if self.connectedControllers.count == 0 - { - return 2 - } - - return 3 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int - { - switch ControllersSettingsSection(rawValue: section)! - { - case .none: return 1 - case .localDevice: return 1 - case .externalControllers: return self.connectedControllers.count - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell - { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) - cell.detailTextLabel?.text = nil - cell.accessoryType = .none + guard let identifier = segue.identifier else { return } - if (indexPath as NSIndexPath).section == ControllersSettingsSection.none.rawValue + switch identifier { + case "controllerInputsSegue": + let controllerInputsViewController = (segue.destination as! UINavigationController).topViewController as! ControllerInputsViewController + controllerInputsViewController.gameController = self.gameController + controllerInputsViewController.system = .snes + + default: break + } + } + + @IBAction private func unwindFromControllerControlsViewController(_ segue: UIStoryboardSegue) + { + } +} + +private extension ControllersSettingsViewController +{ + func configure(_ cell: UITableViewCell, for indexPath: IndexPath) + { + cell.accessoryType = .none + cell.detailTextLabel?.text = nil + cell.textLabel?.textColor = .darkText + + switch Section(rawValue: indexPath.section)! + { + case .none: cell.textLabel?.text = NSLocalizedString("None", comment: "") if Settings.localControllerPlayerIndex != self.playerIndex && !self.connectedControllers.contains(where: { $0.playerIndex == self.playerIndex }) { cell.accessoryType = .checkmark } - } - else - { - let controller: ExternalController - if (indexPath as NSIndexPath).section == ControllersSettingsSection.localDevice.rawValue + case .localDevice, .externalControllers: + let controller: GameController + + if indexPath.section == Section.localDevice.rawValue { controller = self.localDeviceController } - else if (indexPath as NSIndexPath).section == ControllersSettingsSection.externalControllers.rawValue + else if indexPath.section == Section.externalControllers.rawValue { - controller = self.connectedControllers[(indexPath as NSIndexPath).row] + controller = self.connectedControllers[indexPath.row] } else { @@ -210,20 +155,177 @@ extension ControllersSettingsViewController { cell.detailTextLabel?.text = NSLocalizedString("Player \(playerIndex + 1)", comment: "") } - + } + + case .customizeControls: + cell.textLabel?.text = NSLocalizedString("Customize Controls…", comment: "") + cell.textLabel?.textColor = self.view.tintColor + } + } +} + +private extension ControllersSettingsViewController +{ + dynamic func externalGameControllerDidConnect(_ notification: Notification) + { + guard let controller = notification.object as? GameController else { return } + + if let playerIndex = controller.playerIndex + { + // Keep connected controllers sorted. + + self.connectedControllers.insert(controller, at: playerIndex) + } + else + { + self.connectedControllers.append(controller) + } + + if let index = self.connectedControllers.index(where: { $0 == controller }) + { + if self.connectedControllers.count == 1 + { + self.tableView.insertSections(IndexSet(integer: Section.externalControllers.rawValue), with: .fade) + } + else + { + self.tableView.insertRows(at: [IndexPath(row: index, section: Section.externalControllers.rawValue)], with: .automatic) + } + } + } + + dynamic func externalGameControllerDidDisconnect(_ notification: Notification) + { + guard let controller = notification.object as? GameController else { return } + + if let index = self.connectedControllers.index(where: { $0 == controller }) + { + self.connectedControllers.remove(at: index) + + if self.connectedControllers.count == 0 + { + self.tableView.deleteSections(IndexSet(integer: Section.externalControllers.rawValue), with: .fade) + } + else + { + self.tableView.deleteRows(at: [IndexPath(row: index, section: Section.externalControllers.rawValue)], with: .automatic) } } + if controller.playerIndex == self.playerIndex + { + self.tableView.reloadSections(IndexSet(integer: Section.none.rawValue), with: .none) + } + } +} + +extension ControllersSettingsViewController +{ + override func numberOfSections(in tableView: UITableView) -> Int + { + if self.connectedControllers.count == 0 + { + return 2 + } + + if self.gameController == nil || Settings.localControllerPlayerIndex == self.playerIndex + { + return 3 + } + + return 4 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int + { + switch Section(rawValue: section)! + { + case .none: return 1 + case .localDevice: return 1 + case .externalControllers: return self.connectedControllers.count + case .customizeControls: return 1 + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell + { + let cell = tableView.dequeueReusableCell(withIdentifier: RSTCellContentGenericCellIdentifier, for: indexPath) + + self.configure(cell, for: indexPath) + return cell } override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch ControllersSettingsSection(rawValue: section)! + switch Section(rawValue: section)! { case .none: return nil case .localDevice: return NSLocalizedString("Local Device", comment: "") case .externalControllers: return self.connectedControllers.count > 0 ? NSLocalizedString("External Controllers", comment: "") : "" + case .customizeControls: return nil } } } + +extension ControllersSettingsViewController +{ + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) + { + let previousIndexPath: IndexPath? + + if let gameController = self.gameController + { + if gameController == self.localDeviceController + { + previousIndexPath = IndexPath(row: 0, section: Section.localDevice.rawValue) + } + else if let row = self.connectedControllers.index(where: { $0 == gameController }) + { + previousIndexPath = IndexPath(row: row, section: Section.externalControllers.rawValue) + } + else + { + previousIndexPath = nil + } + } + else + { + previousIndexPath = IndexPath(row: 0, section: Section.none.rawValue) + } + + switch Section(rawValue: indexPath.section)! + { + case .none: self.gameController = nil + case .localDevice: self.gameController = self.localDeviceController + case .externalControllers: self.gameController = self.connectedControllers[indexPath.row] + case .customizeControls: + guard let cell = tableView.cellForRow(at: indexPath) else { return } + self.performSegue(withIdentifier: "controllerInputsSegue", sender: cell) + + return + } + + self.tableView.beginUpdates() + + if let previousIndexPath = previousIndexPath, let cell = tableView.cellForRow(at: previousIndexPath) + { + // Must configure cell directly, or else a strange animation occurs when reloading row on iOS 11. + self.configure(cell, for: previousIndexPath) + } + + self.tableView.reloadRows(at: [indexPath], with: .none) + + + if self.numberOfSections(in: self.tableView) > self.tableView.numberOfSections + { + self.tableView.insertSections(IndexSet(integer: Section.customizeControls.rawValue), with: .fade) + } + else if self.numberOfSections(in: self.tableView) < self.tableView.numberOfSections + { + self.tableView.deleteSections(IndexSet(integer: Section.customizeControls.rawValue), with: .fade) + } + + self.tableView.endUpdates() + } +} diff --git a/Delta/Settings/Controllers/InputCalloutView.swift b/Delta/Settings/Controllers/InputCalloutView.swift new file mode 100644 index 0000000..b6c0d7a --- /dev/null +++ b/Delta/Settings/Controllers/InputCalloutView.swift @@ -0,0 +1,84 @@ +// +// InputCalloutView.swift +// Delta +// +// Created by Riley Testut on 7/9/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import SMCalloutView + +import DeltaCore + +extension InputCalloutView +{ + enum State + { + case normal + case listening + } +} + +class InputCalloutView: SMCalloutView +{ + var input: Input? { + didSet { + self.updateState() + } + } + + var state: State = .normal { + didSet { + self.updateState() + } + } + + fileprivate let textLabel: UILabel + + init() + { + self.textLabel = UILabel() + self.textLabel.font = UIFont.boldSystemFont(ofSize: 18.0) + self.textLabel.textAlignment = .center + + super.init(frame: CGRect.zero) + + self.titleView = self.textLabel + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func tintColorDidChange() + { + super.tintColorDidChange() + + self.updateTintColor() + } +} + +private extension InputCalloutView +{ + func updateState() + { + switch self.state + { + case .normal: self.textLabel.text = self.input?.localizedName + case .listening: self.textLabel.text = NSLocalizedString("Press Button", comment: "") + } + + self.updateTintColor() + + self.textLabel.sizeToFit() + } + + func updateTintColor() + { + switch self.state + { + case .normal: self.textLabel.textColor = self.tintColor + case .listening: self.textLabel.textColor = .red + } + } +} diff --git a/Delta/Settings/Settings.storyboard b/Delta/Settings/Settings.storyboard index 73450e5..b4b9f34 100644 --- a/Delta/Settings/Settings.storyboard +++ b/Delta/Settings/Settings.storyboard @@ -1,11 +1,11 @@ - + - + @@ -29,7 +29,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -257,7 +329,7 @@ - - - @@ -284,9 +353,11 @@ + + + - @@ -416,7 +487,7 @@ - + @@ -428,5 +499,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Delta/Settings/SettingsViewController.swift b/Delta/Settings/SettingsViewController.swift index c4fe7d3..97cb7f4 100644 --- a/Delta/Settings/SettingsViewController.swift +++ b/Delta/Settings/SettingsViewController.swift @@ -46,8 +46,8 @@ class SettingsViewController: UITableViewController { super.init(coder: aDecoder) - NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.externalControllerDidConnect(_:)), name: .externalControllerDidConnect, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.externalControllerDidDisconnect(_:)), name: .externalControllerDidDisconnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.externalGameControllerDidConnect(_:)), name: .externalGameControllerDidConnect, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.externalGameControllerDidDisconnect(_:)), name: .externalGameControllerDidDisconnect, object: nil) } override func viewDidLoad() @@ -64,6 +64,13 @@ class SettingsViewController: UITableViewController if let indexPath = self.tableView.indexPathForSelectedRow { + if indexPath.section == Section.controllers.rawValue + { + // Update and temporarily re-select selected row. + self.tableView.reloadSections(IndexSet(integer: Section.controllers.rawValue), with: .none) + self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.none) + } + self.tableView.deselectRow(at: indexPath, animated: true) } } @@ -111,18 +118,6 @@ private extension SettingsViewController } } -private extension SettingsViewController -{ - @IBAction func unwindFromControllersSettingsViewController(_ segue: UIStoryboardSegue) - { - let indexPath = self.tableView.indexPathForSelectedRow - - self.tableView.reloadSections(IndexSet(integer: Section.controllers.rawValue), with: .none) - - self.tableView.selectRow(at: indexPath, animated: true, scrollPosition: UITableViewScrollPosition.none) - } -} - private extension SettingsViewController { @IBAction func beginChangingControllerOpacity(with sender: UISlider) @@ -154,12 +149,12 @@ private extension SettingsViewController private extension SettingsViewController { - dynamic func externalControllerDidConnect(_ notification: Notification) + dynamic func externalGameControllerDidConnect(_ notification: Notification) { self.tableView.reloadSections(IndexSet(integer: Section.controllers.rawValue), with: .none) } - dynamic func externalControllerDidDisconnect(_ notification: Notification) + dynamic func externalGameControllerDidDisconnect(_ notification: Notification) { self.tableView.reloadSections(IndexSet(integer: Section.controllers.rawValue), with: .none) } @@ -190,9 +185,9 @@ extension SettingsViewController { cell.detailTextLabel?.text = UIDevice.current.name } - else if let index = ExternalControllerManager.shared.connectedControllers.index(where: { $0.playerIndex == indexPath.row }) + else if let index = ExternalGameControllerManager.shared.connectedControllers.index(where: { $0.playerIndex == indexPath.row }) { - let controller = ExternalControllerManager.shared.connectedControllers[index] + let controller = ExternalGameControllerManager.shared.connectedControllers[index] cell.detailTextLabel?.text = controller.name } else @@ -211,7 +206,7 @@ extension SettingsViewController { let cell = tableView.cellForRow(at: indexPath) let section = Section(rawValue: indexPath.section)! - + switch section { case Section.controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell) diff --git a/Podfile b/Podfile index b2c3b4a..e6bd722 100644 --- a/Podfile +++ b/Podfile @@ -9,6 +9,7 @@ target 'Delta' do pod 'SDWebImage', '~> 3.8' pod 'Fabric', '~> 1.6.0' pod 'Crashlytics', '~> 3.8.0' + pod 'SMCalloutView' end post_install do |installer| diff --git a/Podfile.lock b/Podfile.lock index c6d6566..7838f15 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -6,6 +6,7 @@ PODS: - SDWebImage (3.8.2): - SDWebImage/Core (= 3.8.2) - SDWebImage/Core (3.8.2) + - SMCalloutView (2.1.5) - SQLite.swift (0.11.3): - SQLite.swift/standard (= 0.11.3) - SQLite.swift/standard (0.11.3) @@ -15,6 +16,7 @@ DEPENDENCIES: - Fabric (~> 1.6.0) - FileMD5Hash (~> 2.0.0) - SDWebImage (~> 3.8) + - SMCalloutView - SQLite.swift (~> 0.11.0) SPEC CHECKSUMS: @@ -22,8 +24,9 @@ SPEC CHECKSUMS: Fabric: 5911403591946b8228ab1c51d98f1d7137e863c6 FileMD5Hash: 3ed69cc19a21ff4d30ae8833fc104275ad2c7de0 SDWebImage: '098e97e6176540799c27e804c96653ee0833d13c' + SMCalloutView: 5c0ee363dc8e7204b2fda17dfad38c93e9e23481 SQLite.swift: 99b36c22084427f0abbeb957556ce1528cf10bb3 -PODFILE CHECKSUM: de6e2bf57dcf8e9fe6b622b181fd87d3855641e6 +PODFILE CHECKSUM: 598f830560ac5b18bbe0eb40134a1719f38f12f1 COCOAPODS: 1.2.1 diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index c6d6566..7838f15 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -6,6 +6,7 @@ PODS: - SDWebImage (3.8.2): - SDWebImage/Core (= 3.8.2) - SDWebImage/Core (3.8.2) + - SMCalloutView (2.1.5) - SQLite.swift (0.11.3): - SQLite.swift/standard (= 0.11.3) - SQLite.swift/standard (0.11.3) @@ -15,6 +16,7 @@ DEPENDENCIES: - Fabric (~> 1.6.0) - FileMD5Hash (~> 2.0.0) - SDWebImage (~> 3.8) + - SMCalloutView - SQLite.swift (~> 0.11.0) SPEC CHECKSUMS: @@ -22,8 +24,9 @@ SPEC CHECKSUMS: Fabric: 5911403591946b8228ab1c51d98f1d7137e863c6 FileMD5Hash: 3ed69cc19a21ff4d30ae8833fc104275ad2c7de0 SDWebImage: '098e97e6176540799c27e804c96653ee0833d13c' + SMCalloutView: 5c0ee363dc8e7204b2fda17dfad38c93e9e23481 SQLite.swift: 99b36c22084427f0abbeb957556ce1528cf10bb3 -PODFILE CHECKSUM: de6e2bf57dcf8e9fe6b622b181fd87d3855641e6 +PODFILE CHECKSUM: 598f830560ac5b18bbe0eb40134a1719f38f12f1 COCOAPODS: 1.2.1 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj index e5d28c5..8fa2f60 100644 --- a/Pods/Pods.xcodeproj/project.pbxproj +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -7,215 +7,239 @@ objects = { /* Begin PBXBuildFile section */ - 098DD319E9D5AE3C4B413F1DCB7245E5 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5CF81D1216A4964304BE11C91A83D5 /* FTS4.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 12CF79798B69B43D77D12724505829EB /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A75411E305B9728E52F9D17FB40749B /* SQLite-Bridging.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 1B1088DAF42D74567A705DC440211D12 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 03968465C6A040B68B9B4E3F0F9F857A /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1C0F95DC71B64C451857A4C991BF2AF8 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A0AE959B5D68C3CB0EE54AFB2DEAF6E /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1CA30DFDE14644203704970B8D9805BC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; - 2888ACC8836D2E79F2F341C32AB3E0B0 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FEA071EB4479A6AF3E7BF5F719A6B2E /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 289C4C0E1B0E975621D177439BCF4B6F /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 012884903390C04A55B7E547DA2B34B5 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 291D6ECA35FE23753F9EFEDA8AB633FC /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA3558CAA80E807627A616811FA5BD6 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2E66668BB25537BCAC6263434F08C9DD /* FileMD5Hash-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 54CF13DAB511ACE04F4CFF9FDF759D51 /* FileMD5Hash-dummy.m */; }; - 32649919900BFE14972CB170A11E7A30 /* SDWebImageDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = FCC7CD02F4721E0FC8931E96B16AB368 /* SDWebImageDecoder.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 3CD0EE70D32733800E902E7C8AFEA79B /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 640D011133223416ECD115481ABE11C6 /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 01F6FD7829922FFEDBA0AC937221139D /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = F9058D96291772916213F878DBC9D4D1 /* UIImage+MultiFormat.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 020AFCE363BBA923E907BD453C394A18 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = A8DD6B2CD921B3CD0CC1C8D285C3DB14 /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 02A3EAB09395DB7996C6A2D6FFEEA541 /* SQLite.swift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 2911054ACE98C26AD58D7BD2727E97E5 /* SQLite.swift-dummy.m */; }; + 05585238F98FFE793DC0D1BA800C0D27 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = B718D0BB0426AD065EABCA59ABA865E3 /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0A108DF7E6F55085A67FC6E0FF9D597B /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8BC0D2A173827BA1039A7C690560FF3 /* Helpers.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 0E8A3312FC090BE373D8B2DC9F33355C /* SMCalloutView.h in Headers */ = {isa = PBXBuildFile; fileRef = F715310E4E9F5621B0A1EE26721C2053 /* SMCalloutView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0E95FFC222F9730AB5A2FA648F3DC10B /* Pods-Delta-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 00B00707EB4D7D4F01732D69B015ADDF /* Pods-Delta-dummy.m */; }; + 14D45BB06714ADAB897AC0F9F5DEEB35 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19EBBFE10B2645507B0A3F484F55BF94 /* CustomFunctions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 19A8DB8810E10682948CBA8F1954F70E /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = 49472E71891AFD1F328838FADB677451 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C5A988FA0C3F4E0F3D81AC3C597B9E8 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44A58B8FBEE6A42E7C1709683A11E5 /* Foundation.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 1FAD25073BF85238A82B39CF64208138 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D1A915C60E1D50527210412A5B4094DD /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 20A087C33B817D962690FDC7E894405A /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = 068FC88E6553ADF63F7B7A7EC8A7E159 /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2207FDE1BA4EE2D34E6465B2C8161FC3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; + 255360BAB2981F4F6C7C2ADFB034DD78 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4584B245DEE3A7D04444B05704046791 /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 29B4C7EBC553B1A96DDE7199EF7EB78A /* SMClassicCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F3E13029C6A72F6947FCFCDD4DB219D /* SMClassicCalloutView.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 29D38081CE6E0C1DC7B78CB2467733EE /* SMCalloutView-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C1E5EE84A074FE94CE4085F1073C5A8 /* SMCalloutView-dummy.m */; }; + 2E66668BB25537BCAC6263434F08C9DD /* FileMD5Hash-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FE3498CA7C8E4CDD1E7F0774B8954505 /* FileMD5Hash-dummy.m */; }; + 307ACA884D90D1B1AF65D152027F8037 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FFDEFB012447BDBE8EEBA4C8646C82A /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3134B683130B4C911A3B1F3269C23C0F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; + 34F15EDD4167886716DE13EF3DA61525 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F6703DD83793C5DD5FAA92B71CB1DCC /* UIButton+WebCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 35ECA1266BE70763C47DB385321C8BDA /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = E6CB37913B03B0D1D9C660198A0BBFD0 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3B7E86A00F8C6E8F5A351516BDFC6E0A /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 9573161D35C02B33C6AB094C1236CB57 /* SDWebImagePrefetcher.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 3BF50196E73DD51E6A1152973DFC27DD /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = EB00990C9F7C2C0808B9C725904197A8 /* SMCalloutView.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 3EEAE0A72D5F8D0397B9DF878F9ABE98 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = BEE873D9C7F8F2001BB54E2DAE25C134 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 405F2E285A1E5033E75EA989DCE7F1BD /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6849DCD50DED973B7F32496C8F6CADC /* Schema.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 44A70B580C1AAD2907574BCA02C3B243 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; - 459009460BFBB3DBB4C9168143FC967E /* SDWebImage-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 043A876B015BB7FB2E06D12EDB0CE561 /* SDWebImage-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4A2DCD3F0F0A15427A7008B45E0D3463 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8758AB01882D93CABAEC02BB1C08B15 /* Operators.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 5172EB82F181CD5C6058720F1EDBFFBA /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B581A01C09D5BEFCAE03AA9CBA0DD88 /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 58C256076C467E9132B30FA203F4682E /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = A4EB749E8B64FB36F3E2A229C14D3E17 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 59757ED380B9FD2D3529CC01940ABC17 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A743D258529CE77D67CFD05E8822D834 /* Setter.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 60C9DBA3EA5D0784AE9C8C87B51BBCF0 /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D35B8054C6A1FB85E1C8AF49DA754AB /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 662C18FEA4DFF9970E8D028B281D97EA /* SDWebImage-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E170474F2A4416367241B2C86D439273 /* SDWebImage-dummy.m */; }; - 66BF4CF3A7E34656616159932E27C6B6 /* FileHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 4865C9E8384997F3382A3CC2772EA009 /* FileHash.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc -w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 679DC0A54440ACE06C668426D960434B /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF069BD2848F152567F822EA1F4F3A5 /* Connection.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 6A00465C6CF90CE73C984F03572BE9C3 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E6F2B93EA109FC734C799B37A5F2C65 /* UIImage+MultiFormat.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 6B70676C9CD3E65704CF5F345A58D7D8 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BF8485A2C5150F9FCC581529A410F3 /* Expression.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 6C88898656689F997079D8C2E02D380B /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 01F7F0FD5C1DD4A57E10338DECBE08BF /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 71A419BAB91B0BECA6617C071891BF3C /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = F3AA6D231072BEA87D8361284B976373 /* UIImageView+WebCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 7487C10F58C60552A3B84C47EF4AABB5 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B14D99E3A060C4422D52E1B43DF44C1 /* SDWebImageDownloader.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 7784F558B74616E8DC1818DA0A0532BC /* Pods-Delta-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CF7D0F0E5A5A95A050C645EA6CDA8D /* Pods-Delta-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7CBFCCC7367FCCF9D53FBFA8ED86BDD7 /* Pods-Delta-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 00B00707EB4D7D4F01732D69B015ADDF /* Pods-Delta-dummy.m */; }; - 7E7C64643C2C3AC5F7CBCC8E044801EF /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = ABE47F73E3A4F0D9C26747F2CCEB862D /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 80C66AC9B65D7A9E73EAF52953078A80 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D90A7E2961E5EDAAE3CD486D46F95F63 /* Foundation.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 81EA3C6ADBF7CCBC1711693AD8966D30 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 730DA6A4D3B2E1433B1F595785D02760 /* Helpers.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 843BDA3C40997300E0B3CB9E27043997 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F6D8E260B72CA343410625FD1A728004 /* SDWebImageDownloaderOperation.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - 85AC71E815A41D4B45A0EB55F9A5DB1E /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = AF307A627BC5C545FD14AF15658B0A20 /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 92C60A4E3797D69E6A7725B12E25C0D0 /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4786611036F85C3646609824CD9563 /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 930D6D8D90701B4A6FD30E94CF42871B /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 84CE5D699E3556BCEA5319CE02EC862B /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9A73EA1D60A6932BDA2B033258B82247 /* SQLite.swift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 802918A5F5E07DF5C0B521963C07FDC1 /* SQLite.swift-dummy.m */; }; - A215B295B907F3FC375FFA644649A845 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33F5EC95A9BDCF263B9E3A69A8762EB1 /* Value.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A3C78AD9387EE296772B1B4031290DE9 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787DA4DEC4DDF799BD316E32E7BDF023 /* Blob.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A5E0B4C7414F681B71DE66C07F4628C4 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 321849DF0ADAD2DFA407B0D629E68647 /* Schema.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A66BC5F91E9B66C05262C55BABAA0421 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DAD08097357C3001C4E61ABB3FA5893 /* UIView+WebCacheOperation.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A66ECB0C1037DD2A24411DF60C9362AE /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = AD6EDB41DF6DFD4BDC3AD9CA119C329E /* UIImage+GIF.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - A7EF436BF7DF4C8640864FBA1BA94351 /* SDWebImageDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = D7F1314060E559C8947FF2156F1A92FC /* SDWebImageDecoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B4D2E6BDA66762C41461DE1466567A22 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFADED5A86C0867B0F0AD1A6EB56B753 /* AggregateFunctions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BCC3E7AF8EAD39EAB60E7F271CAAF5D7 /* FileMD5Hash-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A60C439A4E5C924E3287AB0551280E2E /* FileMD5Hash-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BCDE9C9E8DDB9FD7F9F0F68200854276 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 6FDE31395137009C3C06B9B76AA85BD0 /* NSData+ImageContentType.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - BE6E1EFB57D60E715B8617336436B7EB /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 635A4BD1CEF7E623C71F97A54BFC3616 /* ImageIO.framework */; }; - C0D6EE693288E4A34090518CEE18269F /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FF2F911B4ACB0BBBE1355C44C19EBEB /* UIButton+WebCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C3351D1B55FD32BBAD9B3335713FBB37 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F30F5EA75539EB97D8BC21E9A952579 /* FTS5.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - C36994840D82BF702EC602A8DEC63223 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB4EF3E67B3AC47FF33241CB33BC723 /* Query.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - CA703680A4DCD9CBED0A35283C5B26AD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; - CE103933627196D2BB63FCFB7DDDE1F0 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = CD6EF89C9FB4BA901403ADC3AA39BEBF /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D1EC729542506D0FF0FEAFC10E544BDC /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = B0A0352CABBA53CE65669E49F7AC1135 /* SDWebImageCompat.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - D7570BC6C11012C5F53C53ABF8187CC6 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 010A46F5A9D7559BB3CCF9ABDBCAFF24 /* SDWebImagePrefetcher.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - E376FD7DF6990EB5D6059FF86AA392DD /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B2407530ACBB22F33CD725A0C500FF /* CoreFunctions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - E5102C928DC86E24E1FA70862A698132 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F44E15D9E3FF0C4C5B7A858FFCA8817 /* RTree.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - E8166EA34E4BEF58C5583C06CFFB0971 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = A296555F1740CDDC85453F15267505CA /* UIImageView+HighlightedWebCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - EA47189A2ADA7ABA3CAD4DAA9C862095 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 11D69CC0585763C69BDC1D626B098E8D /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EAF8AC345B2B68E07E239E83AACF81E3 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D434BFEF549B14BDA9F9F9350AD2065E /* Collation.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - EC8F07E15821E96F36AE89560D864FCD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; - EEF3F3825344DF5B3B1F91C8B3D92F81 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB55F6E76B1B3E9EBDD7386FA559CCCF /* CustomFunctions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F16B42DA86FEF3A85DD46658B962B61D /* FileHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 25DF9947D404F6880E23C1E804CA53BF /* FileHash.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F70F77BB9BD4B473EF5731A958F6CFB4 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6986B87CC0ACC355E1901676484D59BA /* Statement.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - F713228AE3D00F1C478CF62077F73AD7 /* SQLite.swift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BD3C5C2AC8B1879B569ADBBDAABD8CB /* SQLite.swift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F86C46E798AA77D74381F0A299724517 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A0B50EB1CF5F290CB62A27072E257F2B /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F97431F8AA6A848ACA072E9DB7DCF5DF /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2745C6E9EBE97C845254602DC1592DF4 /* SDWebImageManager.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; - FEE67933F477210286CDEC86E60D32FF /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = C57D8C69AD898251C5890F970E78AB4F /* SDImageCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 483BC893AE648B89F28763CC2FE1932A /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDE2E8B6DB2458ED0D0AEB620C82C33 /* FTS4.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 4BFD33775F72F952206DA9101BA849A2 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = B02313ED3C98F0D9E8E673D608674FF0 /* UIView+WebCacheOperation.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 53A1E27B96743AF1526979D7C407B36E /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 73648FFFD6172035C937058B26803D6D /* SDImageCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 593AA045F16ABDD2E0C216A6693160A6 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C453C51E8BE33C2E172E40B18626329 /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5EBA645F49A7944F9D5DE1DE7214B16C /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE04DBF47CF0621A6F64E90ECCEC74F2 /* RTree.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 65C3F0B49DCF090CFC1A57B581B7D5EE /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA433B1A2192D12009D581B153C3004 /* Value.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 66BF4CF3A7E34656616159932E27C6B6 /* FileHash.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D4D4C83D4D81FF7570317D601B83DE /* FileHash.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc -w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 67A9DED3A799C2C1B3190757AF74C869 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = A23D5152FE861FB5B1D4950073960C6E /* NSData+ImageContentType.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 69E9B37E0394A6C87B37648633198916 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652D47B5A7FD5E5026907CC2F6B79153 /* Setter.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 7BC82A3FB797473493834376FB76E54E /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ECC54F33ED71354DF6CCCBE4668EEC3 /* CoreFunctions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 7E1E4E7C559B3DCBC6FB1E3F91303A61 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 032AB538856BB66C33BCF3A6EFEBAEDC /* UIImageView+HighlightedWebCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 8288FE73D4A817A73306848AF872DD3B /* SMCalloutView-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F4A02F29281568B9C5A5FDAE342EB996 /* SMCalloutView-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 867ED479D87B069987F16CC84F1CB314 /* SDWebImageDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B3B201E9287A29A9C7DB3E6E89A7C60 /* SDWebImageDecoder.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + 8F7D92A4E63CC4056DFD5C0B1FD14910 /* SQLite.swift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F74AD19F091053437017F0F5538899C /* SQLite.swift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A41E5A0EF327ED9DF2D2866EF78F30A5 /* SMClassicCalloutView.h in Headers */ = {isa = PBXBuildFile; fileRef = 77F129F1BA8E7E54902E13651560B797 /* SMClassicCalloutView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A5F83FD5E39A40A303AEE42994F6BB2D /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 72FC743DB5B7231D4A588B65D80A72CD /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A8274F6E16ECE48FB9139B8456A31201 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = F277C21C6DB430322178CF427005E784 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AB4F3A463C806CFD7BD412DC96CCA6FF /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77CAA2EA8CD0D523E4CBE3D20712BE02 /* Blob.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + AD541D0CA07079BA817282E47531170C /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 635A4BD1CEF7E623C71F97A54BFC3616 /* ImageIO.framework */; }; + AF71FA11F33D4FF8286DE4191247F4B9 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = CDB4230F44759F4F6161E3A256B3BB05 /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B4FF0763F545E55DDF9FB358526B21C5 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = EBD8E993B110532376D18B7F68AB317A /* UIImageView+WebCache.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + B5C757D4F5CE144EBC972BC0EDA42EBC /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624F168E4CA14615A9D78854E7A933D5 /* Expression.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + B771F2C5509A5462CC27977AECB8A05E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; + B9AC8B5C153CD4028E20BDA493F3E8E9 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 36D00FF6092D42D9710DAB8238D6B0F4 /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BACF769130EA8F084781334E3F5487D6 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = 527BDC649D5F7705A1725233BEC21CEC /* UIImage+GIF.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + BB19B505BC3000C14CD0C6539F716F6F /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 83AD613EABACF4F682DD38C393197F4E /* SDWebImageManager.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + BC369BDF43EB991D6BDA5C129249D052 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */; }; + BC7F01C05460B87B4BD3597D8CFEDDD0 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC2C0F90270E994FEDF6FDB780D88A68 /* Connection.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + BCC3E7AF8EAD39EAB60E7F271CAAF5D7 /* FileMD5Hash-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C43F044D76D5174F1A3472D15441FAC9 /* FileMD5Hash-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD93645C73A232461BAFDCD2D583A48F /* SDWebImage-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 52C0F64FF5BD9D05D0DDD439AB4B4B4C /* SDWebImage-dummy.m */; }; + CB0C7E4A7184D8CB11F07ABB7E01BCBF /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 286FB5B86F6E898E75403C870CC05011 /* SDWebImageDownloaderOperation.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + D1AB6379EC7678A60E7A342E19CD7463 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AACB33C34A87776F6D89F7C7D999F2FE /* AggregateFunctions.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + D1B81917966545E8201CA9A7C53EAD86 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = C7966176FA5D69F9D29BD871712BC02C /* SDWebImageDownloader.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + D47F030F3EE8210B84E275A72194BD50 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D1BEC9E736FAF5A1F921744894A5521 /* SDWebImageCompat.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + D5F611A196AB19B6B27BC91E0F7CDF98 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC2AEB033F145B0003C677FD35C0CBEE /* Operators.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + D76E41A83001A863D0EF9A3F0EC0F68B /* SDWebImageDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 40A8B4F2D02BC863608186A20E0C9C0D /* SDWebImageDecoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DC0D674B7D20F83A7A5BAEEE4F00AFB5 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34C5308CB41A391DE8F14481B181BF8 /* Query.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + DD3018D33ABEB0BAA61C562F8A5FFC45 /* SDWebImage-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 19644E545E27F0ABCAEA0D43C6DFB21E /* SDWebImage-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E282C5080C3257C180B32B1F15F2842E /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 32F29B2603D0AC4578F3F268097EF73E /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E4A2641C95DDD1AEE0BA851321A07FC8 /* Pods-Delta-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CF7D0F0E5A5A95A050C645EA6CDA8D /* Pods-Delta-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E70CE29F92FC143D25EBAB0AA0FF7847 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = 316F67B44DF5AB3889A51771534E09FB /* SQLite-Bridging.m */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + F01610EE244331A9AE359D92682841FB /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 87ED074865B1A0718B5980D1F6B32FD3 /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F16B42DA86FEF3A85DD46658B962B61D /* FileHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F58644292785B4F7A515DB8B0CDEDD6 /* FileHash.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F76BA2CF262298B5E751146776A25CB2 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A3AE2A19B33430DE7A53B69F388DA5D /* Statement.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + FC2D34D5B376D1F700CAFB0E04439235 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E3FC8531E544D920F83AC90536903AD /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FD11B32C2CBEDD81033179121AAB5D2D /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD521181E9EA6EFB3C5D81835A4D448E /* Collation.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; + FDEAC6DF3D7044CA7FDD15A185183C2C /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACB861F144099C23DDBE864FB0C028E4 /* FTS5.swift */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 43751C8F4A1E0FED8A513B6C736B2141 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; - proxyType = 1; - remoteGlobalIDString = D88F755329BB917F99DFC5405AC691FE; - remoteInfo = SQLite.swift; - }; - B1786652CDC10C9D41868B80152892A5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 95AEAD50DEA1563D4D1E2AD6EEE0E7B4; - remoteInfo = SDWebImage; - }; - F1D70524142DB2A888CA1F6E3F0F67CC /* PBXContainerItemProxy */ = { + 0E57566421DC7C04ED10FBFF02AE3217 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = 924057B2A88FC4B5526EC3FC7483ABE2; remoteInfo = FileMD5Hash; }; + 387F41711D87C3D2C8716FF754189765 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = E02CAC9BD02FC53AAA763EA4830E4884; + remoteInfo = SDWebImage; + }; + 3AAE57E02BD6B50C58159D299DCA0C4F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = D71D7949D6292CD21BE206D00103E682; + remoteInfo = SQLite.swift; + }; + 7713FF1D874368FBE2D22D4E4CB7C6A7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5A0A16E27351F849E411E94C505CF452; + remoteInfo = SMCalloutView; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 00B00707EB4D7D4F01732D69B015ADDF /* Pods-Delta-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Delta-dummy.m"; sourceTree = ""; }; - 010A46F5A9D7559BB3CCF9ABDBCAFF24 /* SDWebImagePrefetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImagePrefetcher.m; path = SDWebImage/SDWebImagePrefetcher.m; sourceTree = ""; }; - 012884903390C04A55B7E547DA2B34B5 /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCacheOperation.h"; path = "SDWebImage/UIView+WebCacheOperation.h"; sourceTree = ""; }; - 01F7F0FD5C1DD4A57E10338DECBE08BF /* SDWebImageDownloader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloader.h; path = SDWebImage/SDWebImageDownloader.h; sourceTree = ""; }; - 03968465C6A040B68B9B4E3F0F9F857A /* NSData+ImageContentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+ImageContentType.h"; path = "SDWebImage/NSData+ImageContentType.h"; sourceTree = ""; }; - 043A876B015BB7FB2E06D12EDB0CE561 /* SDWebImage-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SDWebImage-umbrella.h"; sourceTree = ""; }; - 0A0AE959B5D68C3CB0EE54AFB2DEAF6E /* SDImageCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDImageCache.h; path = SDWebImage/SDImageCache.h; sourceTree = ""; }; - 0B33A43387DF59869F2A6002F1DC3785 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SQLite.framework; path = SQLite.swift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0B581A01C09D5BEFCAE03AA9CBA0DD88 /* SQLite-Bridging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "SQLite-Bridging.h"; path = "Sources/SQLiteObjc/include/SQLite-Bridging.h"; sourceTree = ""; }; - 11D69CC0585763C69BDC1D626B098E8D /* SQLite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SQLite.h; path = Sources/SQLite/SQLite.h; sourceTree = ""; }; + 0159C36B78547E23EBA1867CAE65F002 /* FileMD5Hash.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FileMD5Hash.framework; path = FileMD5Hash.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 032AB538856BB66C33BCF3A6EFEBAEDC /* UIImageView+HighlightedWebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+HighlightedWebCache.m"; path = "SDWebImage/UIImageView+HighlightedWebCache.m"; sourceTree = ""; }; + 061C525038BE58FCE9A6013CBA4162B5 /* SMCalloutView.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SMCalloutView.xcconfig; sourceTree = ""; }; + 068FC88E6553ADF63F7B7A7EC8A7E159 /* SQLite-Bridging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "SQLite-Bridging.h"; path = "Sources/SQLiteObjc/include/SQLite-Bridging.h"; sourceTree = ""; }; + 0BC95251B8ED1E506925B002BC5B1352 /* SMCalloutView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SMCalloutView.framework; path = SMCalloutView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0EA433B1A2192D12009D581B153C3004 /* Value.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Value.swift; path = Sources/SQLite/Core/Value.swift; sourceTree = ""; }; + 16C12BA1CDC4BAA71A94C08D894DAE28 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SDWebImage.framework; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 19644E545E27F0ABCAEA0D43C6DFB21E /* SDWebImage-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SDWebImage-umbrella.h"; sourceTree = ""; }; + 19EBBFE10B2645507B0A3F484F55BF94 /* CustomFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomFunctions.swift; path = Sources/SQLite/Typed/CustomFunctions.swift; sourceTree = ""; }; + 1BE982AA859EE1A9210D02D6E759A38A /* FileMD5Hash.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = FileMD5Hash.modulemap; sourceTree = ""; }; 1C3BA8511D0F025064897F6EC408296A /* Pods-Delta.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Delta.debug.xcconfig"; sourceTree = ""; }; - 1F472FCBF6D7A7E203EFD6D37EC6B739 /* SQLite.swift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = SQLite.swift.modulemap; sourceTree = ""; }; - 25DF9947D404F6880E23C1E804CA53BF /* FileHash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FileHash.h; path = Library/FileHash.h; sourceTree = ""; }; - 2745C6E9EBE97C845254602DC1592DF4 /* SDWebImageManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageManager.m; path = SDWebImage/SDWebImageManager.m; sourceTree = ""; }; - 28427A69E2775DB52F24BABAC3F45F22 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 2F5CF81D1216A4964304BE11C91A83D5 /* FTS4.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS4.swift; path = Sources/SQLite/Extensions/FTS4.swift; sourceTree = ""; }; - 31B7E048CEBB667B0795D7399EA829AF /* SDWebImage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SDWebImage.xcconfig; sourceTree = ""; }; - 321849DF0ADAD2DFA407B0D629E68647 /* Schema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = Sources/SQLite/Typed/Schema.swift; sourceTree = ""; }; - 32CA5695E88A5637B79D100F29969924 /* Pods_Delta.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Delta.framework; path = "Pods-Delta.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33F5EC95A9BDCF263B9E3A69A8762EB1 /* Value.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Value.swift; path = Sources/SQLite/Core/Value.swift; sourceTree = ""; }; + 1DEFD8D91DD8CE3B57B0A51BDB561E2D /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Fabric.framework; path = iOS/Fabric.framework; sourceTree = ""; }; + 1F46051C1128C9358A3A710DEB82AA24 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 286FB5B86F6E898E75403C870CC05011 /* SDWebImageDownloaderOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloaderOperation.m; path = SDWebImage/SDWebImageDownloaderOperation.m; sourceTree = ""; }; + 2911054ACE98C26AD58D7BD2727E97E5 /* SQLite.swift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SQLite.swift-dummy.m"; sourceTree = ""; }; + 297EC254820663D220F6542C0027C9FE /* SQLite.swift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-prefix.pch"; sourceTree = ""; }; + 2D1BEC9E736FAF5A1F921744894A5521 /* SDWebImageCompat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCompat.m; path = SDWebImage/SDWebImageCompat.m; sourceTree = ""; }; + 2D6E5A84EF07D22B853F28AE193B4E53 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2F3E13029C6A72F6947FCFCDD4DB219D /* SMClassicCalloutView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = SMClassicCalloutView.m; sourceTree = ""; }; + 2F44A58B8FBEE6A42E7C1709683A11E5 /* Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Foundation.swift; path = Sources/SQLite/Foundation.swift; sourceTree = ""; }; + 2F58644292785B4F7A515DB8B0CDEDD6 /* FileHash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FileHash.h; path = Library/FileHash.h; sourceTree = ""; }; + 2FD50D8325E1E8D2B0953062797E6E02 /* SQLite.swift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SQLite.swift.xcconfig; sourceTree = ""; }; + 316F67B44DF5AB3889A51771534E09FB /* SQLite-Bridging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "SQLite-Bridging.m"; path = "Sources/SQLiteObjc/SQLite-Bridging.m"; sourceTree = ""; }; + 32F29B2603D0AC4578F3F268097EF73E /* UIImageView+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+WebCache.h"; path = "SDWebImage/UIImageView+WebCache.h"; sourceTree = ""; }; + 35F61CA9D7252A9F19BF21470AEF205A /* SQLite.swift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = SQLite.swift.modulemap; sourceTree = ""; }; + 36D00FF6092D42D9710DAB8238D6B0F4 /* SDWebImagePrefetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImagePrefetcher.h; path = SDWebImage/SDWebImagePrefetcher.h; sourceTree = ""; }; 393CFF172E48171DCE02DEF123ED6B4F /* Pods-Delta-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Delta-resources.sh"; sourceTree = ""; }; - 4229A636D4EEF4D2C5523CA222ADB9B2 /* ANSCompatibility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ANSCompatibility.h; path = iOS/Crashlytics.framework/Headers/ANSCompatibility.h; sourceTree = ""; }; - 4865C9E8384997F3382A3CC2772EA009 /* FileHash.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FileHash.m; path = Library/FileHash.m; sourceTree = ""; }; - 528DB6818DAAEB5F7FDC1B8D9A4A26BA /* SQLite.swift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-prefix.pch"; sourceTree = ""; }; - 54CF13DAB511ACE04F4CFF9FDF759D51 /* FileMD5Hash-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FileMD5Hash-dummy.m"; sourceTree = ""; }; - 5A75411E305B9728E52F9D17FB40749B /* SQLite-Bridging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "SQLite-Bridging.m"; path = "Sources/SQLiteObjc/SQLite-Bridging.m"; sourceTree = ""; }; - 5E6F2B93EA109FC734C799B37A5F2C65 /* UIImage+MultiFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+MultiFormat.m"; path = "SDWebImage/UIImage+MultiFormat.m"; sourceTree = ""; }; - 5FEA071EB4479A6AF3E7BF5F719A6B2E /* SDWebImageCompat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageCompat.h; path = SDWebImage/SDWebImageCompat.h; sourceTree = ""; }; - 61A3B47FEA2DAE48B17702C888054593 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Fabric.framework; path = iOS/Fabric.framework; sourceTree = ""; }; + 3A3AE2A19B33430DE7A53B69F388DA5D /* Statement.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Statement.swift; path = Sources/SQLite/Core/Statement.swift; sourceTree = ""; }; + 3C1E5EE84A074FE94CE4085F1073C5A8 /* SMCalloutView-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SMCalloutView-dummy.m"; sourceTree = ""; }; + 3F74AD19F091053437017F0F5538899C /* SQLite.swift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-umbrella.h"; sourceTree = ""; }; + 40A8B4F2D02BC863608186A20E0C9C0D /* SDWebImageDecoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDecoder.h; path = SDWebImage/SDWebImageDecoder.h; sourceTree = ""; }; + 4584B245DEE3A7D04444B05704046791 /* SDWebImageManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageManager.h; path = SDWebImage/SDWebImageManager.h; sourceTree = ""; }; + 49472E71891AFD1F328838FADB677451 /* UIImage+GIF.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+GIF.h"; path = "SDWebImage/UIImage+GIF.h"; sourceTree = ""; }; + 4C4C366461DA3B92968A67361C700AB8 /* Answers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Answers.h; path = iOS/Crashlytics.framework/Headers/Answers.h; sourceTree = ""; }; + 4E1FBC10E4C47720883970DAA89DFF1B /* CLSStackFrame.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSStackFrame.h; path = iOS/Crashlytics.framework/Headers/CLSStackFrame.h; sourceTree = ""; }; + 4E3FC8531E544D920F83AC90536903AD /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCacheOperation.h"; path = "SDWebImage/UIView+WebCacheOperation.h"; sourceTree = ""; }; + 4E665218EE93EC4DF2ED23D10582E0BD /* FABAttributes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FABAttributes.h; path = iOS/Fabric.framework/Headers/FABAttributes.h; sourceTree = ""; }; + 527BDC649D5F7705A1725233BEC21CEC /* UIImage+GIF.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+GIF.m"; path = "SDWebImage/UIImage+GIF.m"; sourceTree = ""; }; + 52C0F64FF5BD9D05D0DDD439AB4B4B4C /* SDWebImage-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SDWebImage-dummy.m"; sourceTree = ""; }; + 5C453C51E8BE33C2E172E40B18626329 /* SDWebImageDownloader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloader.h; path = SDWebImage/SDWebImageDownloader.h; sourceTree = ""; }; + 5F6703DD83793C5DD5FAA92B71CB1DCC /* UIButton+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIButton+WebCache.m"; path = "SDWebImage/UIButton+WebCache.m"; sourceTree = ""; }; 61D07C2D20A62CF35439BF6540AAF69F /* Pods-Delta-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Delta-acknowledgements.markdown"; sourceTree = ""; }; + 624F168E4CA14615A9D78854E7A933D5 /* Expression.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Expression.swift; path = Sources/SQLite/Typed/Expression.swift; sourceTree = ""; }; 635A4BD1CEF7E623C71F97A54BFC3616 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/ImageIO.framework; sourceTree = DEVELOPER_DIR; }; - 640D011133223416ECD115481ABE11C6 /* UIButton+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIButton+WebCache.h"; path = "SDWebImage/UIButton+WebCache.h"; sourceTree = ""; }; - 64BBAED01933096F1844A17E2A6E9ECF /* FileMD5Hash.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FileMD5Hash.framework; path = FileMD5Hash.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 66B0F704A80D32419F2FEA268A7996C6 /* SDWebImage.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = SDWebImage.modulemap; sourceTree = ""; }; + 652D47B5A7FD5E5026907CC2F6B79153 /* Setter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Setter.swift; path = Sources/SQLite/Typed/Setter.swift; sourceTree = ""; }; 6701BAAE1472B7CB200DB15361C648B4 /* Pods-Delta-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Delta-frameworks.sh"; sourceTree = ""; }; - 6986B87CC0ACC355E1901676484D59BA /* Statement.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Statement.swift; path = Sources/SQLite/Core/Statement.swift; sourceTree = ""; }; - 6B14D99E3A060C4422D52E1B43DF44C1 /* SDWebImageDownloader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloader.m; path = SDWebImage/SDWebImageDownloader.m; sourceTree = ""; }; - 6BD3C5C2AC8B1879B569ADBBDAABD8CB /* SQLite.swift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-umbrella.h"; sourceTree = ""; }; 6CE29CF4FF5C02028C0A06EC0D2A6120 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - 6D35B8054C6A1FB85E1C8AF49DA754AB /* SDWebImageManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageManager.h; path = SDWebImage/SDWebImageManager.h; sourceTree = ""; }; - 6FDE31395137009C3C06B9B76AA85BD0 /* NSData+ImageContentType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+ImageContentType.m"; path = "SDWebImage/NSData+ImageContentType.m"; sourceTree = ""; }; - 70BF8485A2C5150F9FCC581529A410F3 /* Expression.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Expression.swift; path = Sources/SQLite/Typed/Expression.swift; sourceTree = ""; }; 70F7F78874A3F503DC5B92E837976CD8 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 730DA6A4D3B2E1433B1F595785D02760 /* Helpers.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Helpers.swift; path = Sources/SQLite/Helpers.swift; sourceTree = ""; }; - 767BB3AD2C467C7104FE45C6C8F6562A /* CLSReport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSReport.h; path = iOS/Crashlytics.framework/Headers/CLSReport.h; sourceTree = ""; }; - 787DA4DEC4DDF799BD316E32E7BDF023 /* Blob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Blob.swift; path = Sources/SQLite/Core/Blob.swift; sourceTree = ""; }; - 79B00D01743155B25B50E8F8E6D590D1 /* Fabric.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Fabric.h; path = iOS/Fabric.framework/Headers/Fabric.h; sourceTree = ""; }; - 7DAD08097357C3001C4E61ABB3FA5893 /* UIView+WebCacheOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCacheOperation.m"; path = "SDWebImage/UIView+WebCacheOperation.m"; sourceTree = ""; }; - 7E0880D76FFD4DB866FA61B3BBE9D8EE /* SQLite.swift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SQLite.swift.xcconfig; sourceTree = ""; }; - 7F44E15D9E3FF0C4C5B7A858FFCA8817 /* RTree.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RTree.swift; path = Sources/SQLite/Extensions/RTree.swift; sourceTree = ""; }; - 7FF2F911B4ACB0BBBE1355C44C19EBEB /* UIButton+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIButton+WebCache.m"; path = "SDWebImage/UIButton+WebCache.m"; sourceTree = ""; }; - 802918A5F5E07DF5C0B521963C07FDC1 /* SQLite.swift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SQLite.swift-dummy.m"; sourceTree = ""; }; - 8062C6597FC1FF18A4104851C60BB9AA /* CLSLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSLogging.h; path = iOS/Crashlytics.framework/Headers/CLSLogging.h; sourceTree = ""; }; - 831972241B2BD8CBBF931711A72293EA /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 84CE5D699E3556BCEA5319CE02EC862B /* SDWebImageOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageOperation.h; path = SDWebImage/SDWebImageOperation.h; sourceTree = ""; }; - 8FD7912E764FCFB88B78726649EB7509 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 72FC743DB5B7231D4A588B65D80A72CD /* SDWebImageOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageOperation.h; path = SDWebImage/SDWebImageOperation.h; sourceTree = ""; }; + 73648FFFD6172035C937058B26803D6D /* SDImageCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDImageCache.m; path = SDWebImage/SDImageCache.m; sourceTree = ""; }; + 77CAA2EA8CD0D523E4CBE3D20712BE02 /* Blob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Blob.swift; path = Sources/SQLite/Core/Blob.swift; sourceTree = ""; }; + 77F129F1BA8E7E54902E13651560B797 /* SMClassicCalloutView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = SMClassicCalloutView.h; sourceTree = ""; }; + 7B3B201E9287A29A9C7DB3E6E89A7C60 /* SDWebImageDecoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDecoder.m; path = SDWebImage/SDWebImageDecoder.m; sourceTree = ""; }; + 83AD613EABACF4F682DD38C393197F4E /* SDWebImageManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageManager.m; path = SDWebImage/SDWebImageManager.m; sourceTree = ""; }; + 87ED074865B1A0718B5980D1F6B32FD3 /* UIButton+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIButton+WebCache.h"; path = "SDWebImage/UIButton+WebCache.h"; sourceTree = ""; }; + 89B0CCDB31FD33BDF5CA65821F697C4F /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8ECC54F33ED71354DF6CCCBE4668EEC3 /* CoreFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CoreFunctions.swift; path = Sources/SQLite/Typed/CoreFunctions.swift; sourceTree = ""; }; + 9260283D302E99A4DF1407BB314DE094 /* Fabric.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Fabric.h; path = iOS/Fabric.framework/Headers/Fabric.h; sourceTree = ""; }; 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 94765FAF281DA3817E9F165B4EC66028 /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = iOS/Crashlytics.framework; sourceTree = ""; }; - 9F30F5EA75539EB97D8BC21E9A952579 /* FTS5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS5.swift; path = Sources/SQLite/Extensions/FTS5.swift; sourceTree = ""; }; - A0B50EB1CF5F290CB62A27072E257F2B /* UIImageView+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+WebCache.h"; path = "SDWebImage/UIImageView+WebCache.h"; sourceTree = ""; }; + 9549FD9572AD09182CBFC5AF4C3806EC /* SDWebImage.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = SDWebImage.modulemap; sourceTree = ""; }; + 9573161D35C02B33C6AB094C1236CB57 /* SDWebImagePrefetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImagePrefetcher.m; path = SDWebImage/SDWebImagePrefetcher.m; sourceTree = ""; }; + 99F8E44ACB5CF087E4BF8F904DE04F47 /* CLSLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSLogging.h; path = iOS/Crashlytics.framework/Headers/CLSLogging.h; sourceTree = ""; }; + 9FFDEFB012447BDBE8EEBA4C8646C82A /* SDImageCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDImageCache.h; path = SDWebImage/SDImageCache.h; sourceTree = ""; }; A1CF7D0F0E5A5A95A050C645EA6CDA8D /* Pods-Delta-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Delta-umbrella.h"; sourceTree = ""; }; - A296555F1740CDDC85453F15267505CA /* UIImageView+HighlightedWebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+HighlightedWebCache.m"; path = "SDWebImage/UIImageView+HighlightedWebCache.m"; sourceTree = ""; }; - A4EB749E8B64FB36F3E2A229C14D3E17 /* SDWebImageDownloaderOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloaderOperation.h; path = SDWebImage/SDWebImageDownloaderOperation.h; sourceTree = ""; }; - A60C439A4E5C924E3287AB0551280E2E /* FileMD5Hash-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FileMD5Hash-umbrella.h"; sourceTree = ""; }; - A743D258529CE77D67CFD05E8822D834 /* Setter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Setter.swift; path = Sources/SQLite/Typed/Setter.swift; sourceTree = ""; }; - ABE47F73E3A4F0D9C26747F2CCEB862D /* UIImage+MultiFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+MultiFormat.h"; path = "SDWebImage/UIImage+MultiFormat.h"; sourceTree = ""; }; - AD6EDB41DF6DFD4BDC3AD9CA119C329E /* UIImage+GIF.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+GIF.m"; path = "SDWebImage/UIImage+GIF.m"; sourceTree = ""; }; - AF307A627BC5C545FD14AF15658B0A20 /* SDWebImagePrefetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImagePrefetcher.h; path = SDWebImage/SDWebImagePrefetcher.h; sourceTree = ""; }; - B0A0352CABBA53CE65669E49F7AC1135 /* SDWebImageCompat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCompat.m; path = SDWebImage/SDWebImageCompat.m; sourceTree = ""; }; - B4B2407530ACBB22F33CD725A0C500FF /* CoreFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CoreFunctions.swift; path = Sources/SQLite/Typed/CoreFunctions.swift; sourceTree = ""; }; - BA04B0DD1946F810D78FBE0D92465776 /* Crashlytics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Crashlytics.h; path = iOS/Crashlytics.framework/Headers/Crashlytics.h; sourceTree = ""; }; + A23D5152FE861FB5B1D4950073960C6E /* NSData+ImageContentType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+ImageContentType.m"; path = "SDWebImage/NSData+ImageContentType.m"; sourceTree = ""; }; + A3EA54BEF017871554C81FBD89870EF7 /* SMCalloutView.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = SMCalloutView.modulemap; sourceTree = ""; }; + A8DD6B2CD921B3CD0CC1C8D285C3DB14 /* SDWebImageCompat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageCompat.h; path = SDWebImage/SDWebImageCompat.h; sourceTree = ""; }; + AACB33C34A87776F6D89F7C7D999F2FE /* AggregateFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AggregateFunctions.swift; path = Sources/SQLite/Typed/AggregateFunctions.swift; sourceTree = ""; }; + ACB861F144099C23DDBE864FB0C028E4 /* FTS5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS5.swift; path = Sources/SQLite/Extensions/FTS5.swift; sourceTree = ""; }; + ACDD71A4691EF17778DC6EACBDAC34F1 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SQLite.framework; path = SQLite.swift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B02313ED3C98F0D9E8E673D608674FF0 /* UIView+WebCacheOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCacheOperation.m"; path = "SDWebImage/UIView+WebCacheOperation.m"; sourceTree = ""; }; + B718D0BB0426AD065EABCA59ABA865E3 /* fts3_tokenizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = Sources/SQLiteObjc/fts3_tokenizer.h; sourceTree = ""; }; + B8BC0D2A173827BA1039A7C690560FF3 /* Helpers.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Helpers.swift; path = Sources/SQLite/Helpers.swift; sourceTree = ""; }; BA1F09AF89D60F53382DF398D3795D71 /* Pods-Delta.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-Delta.modulemap"; sourceTree = ""; }; - BA4786611036F85C3646609824CD9563 /* fts3_tokenizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = Sources/SQLiteObjc/fts3_tokenizer.h; sourceTree = ""; }; - BADE19611F17CD7F597B532CB6A624D9 /* SDWebImage-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SDWebImage-prefix.pch"; sourceTree = ""; }; - BB55F6E76B1B3E9EBDD7386FA559CCCF /* CustomFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomFunctions.swift; path = Sources/SQLite/Typed/CustomFunctions.swift; sourceTree = ""; }; - BF7E411A665A8D2DE646C1E193DBE6E0 /* CLSStackFrame.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSStackFrame.h; path = iOS/Crashlytics.framework/Headers/CLSStackFrame.h; sourceTree = ""; }; - C57D8C69AD898251C5890F970E78AB4F /* SDImageCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDImageCache.m; path = SDWebImage/SDImageCache.m; sourceTree = ""; }; - C985A70EDE1912C3FA5744F559FAEAA7 /* Answers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Answers.h; path = iOS/Crashlytics.framework/Headers/Answers.h; sourceTree = ""; }; - CB5685E217F7B2F7EDAAC619C783CDDA /* FileMD5Hash.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FileMD5Hash.xcconfig; sourceTree = ""; }; - CCC9BBCECDFC98343DDF11E5BD5995AA /* FABAttributes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FABAttributes.h; path = iOS/Fabric.framework/Headers/FABAttributes.h; sourceTree = ""; }; - CD4078DAC643CC8DC9C97A24BEACFCDB /* FileMD5Hash-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FileMD5Hash-prefix.pch"; sourceTree = ""; }; - CD6EF89C9FB4BA901403ADC3AA39BEBF /* UIImage+GIF.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+GIF.h"; path = "SDWebImage/UIImage+GIF.h"; sourceTree = ""; }; - CDB4EF3E67B3AC47FF33241CB33BC723 /* Query.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Query.swift; path = Sources/SQLite/Typed/Query.swift; sourceTree = ""; }; - D08836B2071BB4727C71D229B96E924B /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SDWebImage.framework; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D434BFEF549B14BDA9F9F9350AD2065E /* Collation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Collation.swift; path = Sources/SQLite/Typed/Collation.swift; sourceTree = ""; }; - D7F1314060E559C8947FF2156F1A92FC /* SDWebImageDecoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDecoder.h; path = SDWebImage/SDWebImageDecoder.h; sourceTree = ""; }; - D8758AB01882D93CABAEC02BB1C08B15 /* Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/SQLite/Typed/Operators.swift; sourceTree = ""; }; - D90A7E2961E5EDAAE3CD486D46F95F63 /* Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Foundation.swift; path = Sources/SQLite/Foundation.swift; sourceTree = ""; }; - DAA3558CAA80E807627A616811FA5BD6 /* UIImageView+HighlightedWebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+HighlightedWebCache.h"; path = "SDWebImage/UIImageView+HighlightedWebCache.h"; sourceTree = ""; }; - DE4FCE080CB8CD46E5E1A3E83A93E058 /* FileMD5Hash.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = FileMD5Hash.modulemap; sourceTree = ""; }; - DFADED5A86C0867B0F0AD1A6EB56B753 /* AggregateFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AggregateFunctions.swift; path = Sources/SQLite/Typed/AggregateFunctions.swift; sourceTree = ""; }; - DFF069BD2848F152567F822EA1F4F3A5 /* Connection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Connection.swift; path = Sources/SQLite/Core/Connection.swift; sourceTree = ""; }; - E170474F2A4416367241B2C86D439273 /* SDWebImage-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SDWebImage-dummy.m"; sourceTree = ""; }; + BA87BC51ECB890A375E8694685FAE8A7 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BC2C0F90270E994FEDF6FDB780D88A68 /* Connection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Connection.swift; path = Sources/SQLite/Core/Connection.swift; sourceTree = ""; }; + BE04DBF47CF0621A6F64E90ECCEC74F2 /* RTree.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RTree.swift; path = Sources/SQLite/Extensions/RTree.swift; sourceTree = ""; }; + BEE873D9C7F8F2001BB54E2DAE25C134 /* UIImageView+HighlightedWebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+HighlightedWebCache.h"; path = "SDWebImage/UIImageView+HighlightedWebCache.h"; sourceTree = ""; }; + C43F044D76D5174F1A3472D15441FAC9 /* FileMD5Hash-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FileMD5Hash-umbrella.h"; sourceTree = ""; }; + C7966176FA5D69F9D29BD871712BC02C /* SDWebImageDownloader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloader.m; path = SDWebImage/SDWebImageDownloader.m; sourceTree = ""; }; + CC2AEB033F145B0003C677FD35C0CBEE /* Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/SQLite/Typed/Operators.swift; sourceTree = ""; }; + CC448D70D2D84A30A4A4D226A8ABD13F /* SDWebImage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SDWebImage.xcconfig; sourceTree = ""; }; + CDB4230F44759F4F6161E3A256B3BB05 /* NSData+ImageContentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+ImageContentType.h"; path = "SDWebImage/NSData+ImageContentType.h"; sourceTree = ""; }; + D1A915C60E1D50527210412A5B4094DD /* SDWebImageDownloaderOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloaderOperation.h; path = SDWebImage/SDWebImageDownloaderOperation.h; sourceTree = ""; }; + D34C5308CB41A391DE8F14481B181BF8 /* Query.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Query.swift; path = Sources/SQLite/Typed/Query.swift; sourceTree = ""; }; + D6849DCD50DED973B7F32496C8F6CADC /* Schema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = Sources/SQLite/Typed/Schema.swift; sourceTree = ""; }; + D7D4D4C83D4D81FF7570317D601B83DE /* FileHash.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FileHash.m; path = Library/FileHash.m; sourceTree = ""; }; + D8C077D2CD74FE7022E6E86BA03B9BAA /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = iOS/Crashlytics.framework; sourceTree = ""; }; + DCDE2E8B6DB2458ED0D0AEB620C82C33 /* FTS4.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS4.swift; path = Sources/SQLite/Extensions/FTS4.swift; sourceTree = ""; }; + DDE976DADC01C9F233C73181B7C677FA /* SDWebImage-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SDWebImage-prefix.pch"; sourceTree = ""; }; + DFB799765277CB092B656E76446C5A75 /* FileMD5Hash.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FileMD5Hash.xcconfig; sourceTree = ""; }; + E52BF635FC2EF1621E67C61344C81C24 /* SMCalloutView-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SMCalloutView-prefix.pch"; sourceTree = ""; }; + E6CB37913B03B0D1D9C660198A0BBFD0 /* UIImage+MultiFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+MultiFormat.h"; path = "SDWebImage/UIImage+MultiFormat.h"; sourceTree = ""; }; EA65B5484E3BB3284577BD4EA4FA7147 /* Pods-Delta.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Delta.release.xcconfig"; sourceTree = ""; }; + EA7149D3D08F2A6BC584BEBC314A9BFB /* ANSCompatibility.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ANSCompatibility.h; path = iOS/Crashlytics.framework/Headers/ANSCompatibility.h; sourceTree = ""; }; + EB00990C9F7C2C0808B9C725904197A8 /* SMCalloutView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = SMCalloutView.m; sourceTree = ""; }; + EBD8E993B110532376D18B7F68AB317A /* UIImageView+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+WebCache.m"; path = "SDWebImage/UIImageView+WebCache.m"; sourceTree = ""; }; EDB35A7ED3324B1E48397C86891B1362 /* Pods-Delta-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Delta-acknowledgements.plist"; sourceTree = ""; }; - F3AA6D231072BEA87D8361284B976373 /* UIImageView+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+WebCache.m"; path = "SDWebImage/UIImageView+WebCache.m"; sourceTree = ""; }; - F6D8E260B72CA343410625FD1A728004 /* SDWebImageDownloaderOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloaderOperation.m; path = SDWebImage/SDWebImageDownloaderOperation.m; sourceTree = ""; }; - F82BC99143F8E7D9502B69521F8954A4 /* CLSAttributes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSAttributes.h; path = iOS/Crashlytics.framework/Headers/CLSAttributes.h; sourceTree = ""; }; - FCC7CD02F4721E0FC8931E96B16AB368 /* SDWebImageDecoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDecoder.m; path = SDWebImage/SDWebImageDecoder.m; sourceTree = ""; }; + F1850435281691489E29EABB9E6D1EE9 /* FileMD5Hash-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FileMD5Hash-prefix.pch"; sourceTree = ""; }; + F277C21C6DB430322178CF427005E784 /* SQLite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SQLite.h; path = Sources/SQLite/SQLite.h; sourceTree = ""; }; + F4A02F29281568B9C5A5FDAE342EB996 /* SMCalloutView-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SMCalloutView-umbrella.h"; sourceTree = ""; }; + F715310E4E9F5621B0A1EE26721C2053 /* SMCalloutView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = SMCalloutView.h; sourceTree = ""; }; + F9058D96291772916213F878DBC9D4D1 /* UIImage+MultiFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+MultiFormat.m"; path = "SDWebImage/UIImage+MultiFormat.m"; sourceTree = ""; }; + F9B93EC3996C232919BB4F98458C45D5 /* Crashlytics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Crashlytics.h; path = iOS/Crashlytics.framework/Headers/Crashlytics.h; sourceTree = ""; }; + FA5CE005707B6583BF9CE4DF86B180DC /* Pods_Delta.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Delta.framework; path = "Pods-Delta.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + FA9BCD1E0FC20F3166C12E76650B9006 /* CLSReport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSReport.h; path = iOS/Crashlytics.framework/Headers/CLSReport.h; sourceTree = ""; }; + FC75BF94BACA3E271CFB55F764B1439B /* CLSAttributes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CLSAttributes.h; path = iOS/Crashlytics.framework/Headers/CLSAttributes.h; sourceTree = ""; }; + FD521181E9EA6EFB3C5D81835A4D448E /* Collation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Collation.swift; path = Sources/SQLite/Typed/Collation.swift; sourceTree = ""; }; + FE3498CA7C8E4CDD1E7F0774B8954505 /* FileMD5Hash-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FileMD5Hash-dummy.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 54F1511A803376CB9F7035A4D9F764D3 /* Frameworks */ = { + 5C0DF94230C9EECDA7269ACD38F80BB8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EC8F07E15821E96F36AE89560D864FCD /* Foundation.framework in Frameworks */, + B771F2C5509A5462CC27977AECB8A05E /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 5DA87AB35B47EC77EC2088FBAF257BF6 /* Frameworks */ = { + 6A87A94DB2110DBC645F09B6863C840A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1CA30DFDE14644203704970B8D9805BC /* Foundation.framework in Frameworks */, - BE6E1EFB57D60E715B8617336436B7EB /* ImageIO.framework in Frameworks */, + BC369BDF43EB991D6BDA5C129249D052 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -227,17 +251,40 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - DA6FF3BA4FD643976251EC15FE2B2DDE /* Frameworks */ = { + 98F7206242604EADE5687F25134FD6E4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CA703680A4DCD9CBED0A35283C5B26AD /* Foundation.framework in Frameworks */, + 2207FDE1BA4EE2D34E6465B2C8161FC3 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D97354725A51F45FDD2257F6907CC168 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3134B683130B4C911A3B1F3269C23C0F /* Foundation.framework in Frameworks */, + AD541D0CA07079BA817282E47531170C /* ImageIO.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 06F093DEB80530D69626327B53498E5F /* Support Files */ = { + isa = PBXGroup; + children = ( + 1BE982AA859EE1A9210D02D6E759A38A /* FileMD5Hash.modulemap */, + DFB799765277CB092B656E76446C5A75 /* FileMD5Hash.xcconfig */, + FE3498CA7C8E4CDD1E7F0774B8954505 /* FileMD5Hash-dummy.m */, + F1850435281691489E29EABB9E6D1EE9 /* FileMD5Hash-prefix.pch */, + C43F044D76D5174F1A3472D15441FAC9 /* FileMD5Hash-umbrella.h */, + 89B0CCDB31FD33BDF5CA65821F697C4F /* Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/FileMD5Hash"; + sourceTree = ""; + }; 07F64EF51F4E28A5F31A5BD497F93D43 /* Pods-Delta */ = { isa = PBXGroup; children = ( @@ -256,22 +303,6 @@ path = "Target Support Files/Pods-Delta"; sourceTree = ""; }; - 0CD7193CB54F38075D52875EBABACFD4 /* Crashlytics */ = { - isa = PBXGroup; - children = ( - 4229A636D4EEF4D2C5523CA222ADB9B2 /* ANSCompatibility.h */, - C985A70EDE1912C3FA5744F559FAEAA7 /* Answers.h */, - F82BC99143F8E7D9502B69521F8954A4 /* CLSAttributes.h */, - 8062C6597FC1FF18A4104851C60BB9AA /* CLSLogging.h */, - 767BB3AD2C467C7104FE45C6C8F6562A /* CLSReport.h */, - BF7E411A665A8D2DE646C1E193DBE6E0 /* CLSStackFrame.h */, - BA04B0DD1946F810D78FBE0D92465776 /* Crashlytics.h */, - 9CE0ED73D0464D6C668DF98A23E10FB9 /* Frameworks */, - ); - name = Crashlytics; - path = Crashlytics; - sourceTree = ""; - }; 1FADA36CBBEBF5DF6696194D87183478 /* iOS */ = { isa = PBXGroup; children = ( @@ -281,18 +312,15 @@ name = iOS; sourceTree = ""; }; - 2EC8A33EBBFE8C0735B0E90198BAEF55 /* Support Files */ = { + 331CA75B5D0363D2AF243E44D661F9A3 /* FileMD5Hash */ = { isa = PBXGroup; children = ( - 831972241B2BD8CBBF931711A72293EA /* Info.plist */, - 1F472FCBF6D7A7E203EFD6D37EC6B739 /* SQLite.swift.modulemap */, - 7E0880D76FFD4DB866FA61B3BBE9D8EE /* SQLite.swift.xcconfig */, - 802918A5F5E07DF5C0B521963C07FDC1 /* SQLite.swift-dummy.m */, - 528DB6818DAAEB5F7FDC1B8D9A4A26BA /* SQLite.swift-prefix.pch */, - 6BD3C5C2AC8B1879B569ADBBDAABD8CB /* SQLite.swift-umbrella.h */, + 2F58644292785B4F7A515DB8B0CDEDD6 /* FileHash.h */, + D7D4D4C83D4D81FF7570317D601B83DE /* FileHash.m */, + 06F093DEB80530D69626327B53498E5F /* Support Files */, ); - name = "Support Files"; - path = "../Target Support Files/SQLite.swift"; + name = FileMD5Hash; + path = FileMD5Hash; sourceTree = ""; }; 433CD3331B6C3787F473C941B61FC68F /* Frameworks */ = { @@ -303,84 +331,93 @@ name = Frameworks; sourceTree = ""; }; - 46B83BF18837301C99F447C003120D73 /* Support Files */ = { + 47016256D64A5202CF9F095C4DCAA1E0 /* standard */ = { isa = PBXGroup; children = ( - 28427A69E2775DB52F24BABAC3F45F22 /* Info.plist */, - 66B0F704A80D32419F2FEA268A7996C6 /* SDWebImage.modulemap */, - 31B7E048CEBB667B0795D7399EA829AF /* SDWebImage.xcconfig */, - E170474F2A4416367241B2C86D439273 /* SDWebImage-dummy.m */, - BADE19611F17CD7F597B532CB6A624D9 /* SDWebImage-prefix.pch */, - 043A876B015BB7FB2E06D12EDB0CE561 /* SDWebImage-umbrella.h */, + AACB33C34A87776F6D89F7C7D999F2FE /* AggregateFunctions.swift */, + 77CAA2EA8CD0D523E4CBE3D20712BE02 /* Blob.swift */, + FD521181E9EA6EFB3C5D81835A4D448E /* Collation.swift */, + BC2C0F90270E994FEDF6FDB780D88A68 /* Connection.swift */, + 8ECC54F33ED71354DF6CCCBE4668EEC3 /* CoreFunctions.swift */, + 19EBBFE10B2645507B0A3F484F55BF94 /* CustomFunctions.swift */, + 624F168E4CA14615A9D78854E7A933D5 /* Expression.swift */, + 2F44A58B8FBEE6A42E7C1709683A11E5 /* Foundation.swift */, + B718D0BB0426AD065EABCA59ABA865E3 /* fts3_tokenizer.h */, + DCDE2E8B6DB2458ED0D0AEB620C82C33 /* FTS4.swift */, + ACB861F144099C23DDBE864FB0C028E4 /* FTS5.swift */, + B8BC0D2A173827BA1039A7C690560FF3 /* Helpers.swift */, + CC2AEB033F145B0003C677FD35C0CBEE /* Operators.swift */, + D34C5308CB41A391DE8F14481B181BF8 /* Query.swift */, + BE04DBF47CF0621A6F64E90ECCEC74F2 /* RTree.swift */, + D6849DCD50DED973B7F32496C8F6CADC /* Schema.swift */, + 652D47B5A7FD5E5026907CC2F6B79153 /* Setter.swift */, + F277C21C6DB430322178CF427005E784 /* SQLite.h */, + 068FC88E6553ADF63F7B7A7EC8A7E159 /* SQLite-Bridging.h */, + 316F67B44DF5AB3889A51771534E09FB /* SQLite-Bridging.m */, + 3A3AE2A19B33430DE7A53B69F388DA5D /* Statement.swift */, + 0EA433B1A2192D12009D581B153C3004 /* Value.swift */, ); - name = "Support Files"; - path = "../Target Support Files/SDWebImage"; + name = standard; sourceTree = ""; }; - 60370E4B9EABA53B20C917C059B11E63 /* Fabric */ = { + 531E03EB9BDA837BD15E5CFA33950AA3 /* Fabric */ = { isa = PBXGroup; children = ( - CCC9BBCECDFC98343DDF11E5BD5995AA /* FABAttributes.h */, - 79B00D01743155B25B50E8F8E6D590D1 /* Fabric.h */, - D4B2E49FCA447FD090EE210ED6CFDC21 /* Frameworks */, + 4E665218EE93EC4DF2ED23D10582E0BD /* FABAttributes.h */, + 9260283D302E99A4DF1407BB314DE094 /* Fabric.h */, + 9D50E7E44A83A074A5B27405071C555A /* Frameworks */, ); name = Fabric; path = Fabric; sourceTree = ""; }; - 6DCC4C02B80FC675A01E718C75BE2915 /* Support Files */ = { + 5427BBB5C33A290393604304A6049893 /* SDWebImage */ = { isa = PBXGroup; children = ( - DE4FCE080CB8CD46E5E1A3E83A93E058 /* FileMD5Hash.modulemap */, - CB5685E217F7B2F7EDAAC619C783CDDA /* FileMD5Hash.xcconfig */, - 54CF13DAB511ACE04F4CFF9FDF759D51 /* FileMD5Hash-dummy.m */, - CD4078DAC643CC8DC9C97A24BEACFCDB /* FileMD5Hash-prefix.pch */, - A60C439A4E5C924E3287AB0551280E2E /* FileMD5Hash-umbrella.h */, - 8FD7912E764FCFB88B78726649EB7509 /* Info.plist */, + 96D9DE7FF8E7331E3EF2EBA90FC85661 /* Core */, + EF5B18EEB9983E18AAF90F03F5AC0920 /* Support Files */, + ); + name = SDWebImage; + path = SDWebImage; + sourceTree = ""; + }; + 6E588658A8888B4B213D36BBF2905D46 /* Products */ = { + isa = PBXGroup; + children = ( + 0159C36B78547E23EBA1867CAE65F002 /* FileMD5Hash.framework */, + FA5CE005707B6583BF9CE4DF86B180DC /* Pods_Delta.framework */, + 16C12BA1CDC4BAA71A94C08D894DAE28 /* SDWebImage.framework */, + 0BC95251B8ED1E506925B002BC5B1352 /* SMCalloutView.framework */, + ACDD71A4691EF17778DC6EACBDAC34F1 /* SQLite.framework */, + ); + name = Products; + sourceTree = ""; + }; + 795312991DF0976E153D01C3DB2D7EFF /* SMCalloutView */ = { + isa = PBXGroup; + children = ( + F715310E4E9F5621B0A1EE26721C2053 /* SMCalloutView.h */, + EB00990C9F7C2C0808B9C725904197A8 /* SMCalloutView.m */, + 77F129F1BA8E7E54902E13651560B797 /* SMClassicCalloutView.h */, + 2F3E13029C6A72F6947FCFCDD4DB219D /* SMClassicCalloutView.m */, + 85F172A17732362EF6633B33B6123F17 /* Support Files */, + ); + name = SMCalloutView; + path = SMCalloutView; + sourceTree = ""; + }; + 7A644872BF34ACF9C88557A1A80046F7 /* Support Files */ = { + isa = PBXGroup; + children = ( + BA87BC51ECB890A375E8694685FAE8A7 /* Info.plist */, + 35F61CA9D7252A9F19BF21470AEF205A /* SQLite.swift.modulemap */, + 2FD50D8325E1E8D2B0953062797E6E02 /* SQLite.swift.xcconfig */, + 2911054ACE98C26AD58D7BD2727E97E5 /* SQLite.swift-dummy.m */, + 297EC254820663D220F6542C0027C9FE /* SQLite.swift-prefix.pch */, + 3F74AD19F091053437017F0F5538899C /* SQLite.swift-umbrella.h */, ); name = "Support Files"; - path = "../Target Support Files/FileMD5Hash"; - sourceTree = ""; - }; - 6EC6C19690E6A0D9577110D76ACD8A39 /* Pods */ = { - isa = PBXGroup; - children = ( - 0CD7193CB54F38075D52875EBABACFD4 /* Crashlytics */, - 60370E4B9EABA53B20C917C059B11E63 /* Fabric */, - A8462AF6298D46025CB78BACDCEF5B02 /* FileMD5Hash */, - 9BE5D9C4A41107E48D04FE4619029174 /* SDWebImage */, - BEFEE191144E4EEBDC1A02ECBFF9D802 /* SQLite.swift */, - ); - name = Pods; - sourceTree = ""; - }; - 798EEB2F4D0C82B198A3C49C04A07F0C /* standard */ = { - isa = PBXGroup; - children = ( - DFADED5A86C0867B0F0AD1A6EB56B753 /* AggregateFunctions.swift */, - 787DA4DEC4DDF799BD316E32E7BDF023 /* Blob.swift */, - D434BFEF549B14BDA9F9F9350AD2065E /* Collation.swift */, - DFF069BD2848F152567F822EA1F4F3A5 /* Connection.swift */, - B4B2407530ACBB22F33CD725A0C500FF /* CoreFunctions.swift */, - BB55F6E76B1B3E9EBDD7386FA559CCCF /* CustomFunctions.swift */, - 70BF8485A2C5150F9FCC581529A410F3 /* Expression.swift */, - D90A7E2961E5EDAAE3CD486D46F95F63 /* Foundation.swift */, - BA4786611036F85C3646609824CD9563 /* fts3_tokenizer.h */, - 2F5CF81D1216A4964304BE11C91A83D5 /* FTS4.swift */, - 9F30F5EA75539EB97D8BC21E9A952579 /* FTS5.swift */, - 730DA6A4D3B2E1433B1F595785D02760 /* Helpers.swift */, - D8758AB01882D93CABAEC02BB1C08B15 /* Operators.swift */, - CDB4EF3E67B3AC47FF33241CB33BC723 /* Query.swift */, - 7F44E15D9E3FF0C4C5B7A858FFCA8817 /* RTree.swift */, - 321849DF0ADAD2DFA407B0D629E68647 /* Schema.swift */, - A743D258529CE77D67CFD05E8822D834 /* Setter.swift */, - 11D69CC0585763C69BDC1D626B098E8D /* SQLite.h */, - 0B581A01C09D5BEFCAE03AA9CBA0DD88 /* SQLite-Bridging.h */, - 5A75411E305B9728E52F9D17FB40749B /* SQLite-Bridging.m */, - 6986B87CC0ACC355E1901676484D59BA /* Statement.swift */, - 33F5EC95A9BDCF263B9E3A69A8762EB1 /* Value.swift */, - ); - name = standard; + path = "../Target Support Files/SQLite.swift"; sourceTree = ""; }; 7DB346D0F39D3F0E887471402A8071AB = { @@ -388,12 +425,26 @@ children = ( 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, 433CD3331B6C3787F473C941B61FC68F /* Frameworks */, - 6EC6C19690E6A0D9577110D76ACD8A39 /* Pods */, - C324234DA460FB6DAF1832F14EE1451F /* Products */, + B2C53D5F4CD7C3A5EA2C240CFAEC0936 /* Pods */, + 6E588658A8888B4B213D36BBF2905D46 /* Products */, 94AA82DA44BA457749B76A54853CD74C /* Targets Support Files */, ); sourceTree = ""; }; + 85F172A17732362EF6633B33B6123F17 /* Support Files */ = { + isa = PBXGroup; + children = ( + 2D6E5A84EF07D22B853F28AE193B4E53 /* Info.plist */, + A3EA54BEF017871554C81FBD89870EF7 /* SMCalloutView.modulemap */, + 061C525038BE58FCE9A6013CBA4162B5 /* SMCalloutView.xcconfig */, + 3C1E5EE84A074FE94CE4085F1073C5A8 /* SMCalloutView-dummy.m */, + E52BF635FC2EF1621E67C61344C81C24 /* SMCalloutView-prefix.pch */, + F4A02F29281568B9C5A5FDAE342EB996 /* SMCalloutView-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/SMCalloutView"; + sourceTree = ""; + }; 94AA82DA44BA457749B76A54853CD74C /* Targets Support Files */ = { isa = PBXGroup; children = ( @@ -402,96 +453,107 @@ name = "Targets Support Files"; sourceTree = ""; }; - 9BE5D9C4A41107E48D04FE4619029174 /* SDWebImage */ = { + 96D9DE7FF8E7331E3EF2EBA90FC85661 /* Core */ = { isa = PBXGroup; children = ( - C08B569CC1D5CC6D09E27E9FACF9465B /* Core */, - 46B83BF18837301C99F447C003120D73 /* Support Files */, + CDB4230F44759F4F6161E3A256B3BB05 /* NSData+ImageContentType.h */, + A23D5152FE861FB5B1D4950073960C6E /* NSData+ImageContentType.m */, + 9FFDEFB012447BDBE8EEBA4C8646C82A /* SDImageCache.h */, + 73648FFFD6172035C937058B26803D6D /* SDImageCache.m */, + A8DD6B2CD921B3CD0CC1C8D285C3DB14 /* SDWebImageCompat.h */, + 2D1BEC9E736FAF5A1F921744894A5521 /* SDWebImageCompat.m */, + 40A8B4F2D02BC863608186A20E0C9C0D /* SDWebImageDecoder.h */, + 7B3B201E9287A29A9C7DB3E6E89A7C60 /* SDWebImageDecoder.m */, + 5C453C51E8BE33C2E172E40B18626329 /* SDWebImageDownloader.h */, + C7966176FA5D69F9D29BD871712BC02C /* SDWebImageDownloader.m */, + D1A915C60E1D50527210412A5B4094DD /* SDWebImageDownloaderOperation.h */, + 286FB5B86F6E898E75403C870CC05011 /* SDWebImageDownloaderOperation.m */, + 4584B245DEE3A7D04444B05704046791 /* SDWebImageManager.h */, + 83AD613EABACF4F682DD38C393197F4E /* SDWebImageManager.m */, + 72FC743DB5B7231D4A588B65D80A72CD /* SDWebImageOperation.h */, + 36D00FF6092D42D9710DAB8238D6B0F4 /* SDWebImagePrefetcher.h */, + 9573161D35C02B33C6AB094C1236CB57 /* SDWebImagePrefetcher.m */, + 87ED074865B1A0718B5980D1F6B32FD3 /* UIButton+WebCache.h */, + 5F6703DD83793C5DD5FAA92B71CB1DCC /* UIButton+WebCache.m */, + 49472E71891AFD1F328838FADB677451 /* UIImage+GIF.h */, + 527BDC649D5F7705A1725233BEC21CEC /* UIImage+GIF.m */, + E6CB37913B03B0D1D9C660198A0BBFD0 /* UIImage+MultiFormat.h */, + F9058D96291772916213F878DBC9D4D1 /* UIImage+MultiFormat.m */, + BEE873D9C7F8F2001BB54E2DAE25C134 /* UIImageView+HighlightedWebCache.h */, + 032AB538856BB66C33BCF3A6EFEBAEDC /* UIImageView+HighlightedWebCache.m */, + 32F29B2603D0AC4578F3F268097EF73E /* UIImageView+WebCache.h */, + EBD8E993B110532376D18B7F68AB317A /* UIImageView+WebCache.m */, + 4E3FC8531E544D920F83AC90536903AD /* UIView+WebCacheOperation.h */, + B02313ED3C98F0D9E8E673D608674FF0 /* UIView+WebCacheOperation.m */, ); - name = SDWebImage; - path = SDWebImage; + name = Core; sourceTree = ""; }; - 9CE0ED73D0464D6C668DF98A23E10FB9 /* Frameworks */ = { + 9D50E7E44A83A074A5B27405071C555A /* Frameworks */ = { isa = PBXGroup; children = ( - 94765FAF281DA3817E9F165B4EC66028 /* Crashlytics.framework */, + 1DEFD8D91DD8CE3B57B0A51BDB561E2D /* Fabric.framework */, ); name = Frameworks; sourceTree = ""; }; - A8462AF6298D46025CB78BACDCEF5B02 /* FileMD5Hash */ = { + A267B4F77F709351A47C49E0765B9726 /* SQLite.swift */ = { isa = PBXGroup; children = ( - 25DF9947D404F6880E23C1E804CA53BF /* FileHash.h */, - 4865C9E8384997F3382A3CC2772EA009 /* FileHash.m */, - 6DCC4C02B80FC675A01E718C75BE2915 /* Support Files */, - ); - name = FileMD5Hash; - path = FileMD5Hash; - sourceTree = ""; - }; - BEFEE191144E4EEBDC1A02ECBFF9D802 /* SQLite.swift */ = { - isa = PBXGroup; - children = ( - 798EEB2F4D0C82B198A3C49C04A07F0C /* standard */, - 2EC8A33EBBFE8C0735B0E90198BAEF55 /* Support Files */, + 47016256D64A5202CF9F095C4DCAA1E0 /* standard */, + 7A644872BF34ACF9C88557A1A80046F7 /* Support Files */, ); name = SQLite.swift; path = SQLite.swift; sourceTree = ""; }; - C08B569CC1D5CC6D09E27E9FACF9465B /* Core */ = { + B2C53D5F4CD7C3A5EA2C240CFAEC0936 /* Pods */ = { isa = PBXGroup; children = ( - 03968465C6A040B68B9B4E3F0F9F857A /* NSData+ImageContentType.h */, - 6FDE31395137009C3C06B9B76AA85BD0 /* NSData+ImageContentType.m */, - 0A0AE959B5D68C3CB0EE54AFB2DEAF6E /* SDImageCache.h */, - C57D8C69AD898251C5890F970E78AB4F /* SDImageCache.m */, - 5FEA071EB4479A6AF3E7BF5F719A6B2E /* SDWebImageCompat.h */, - B0A0352CABBA53CE65669E49F7AC1135 /* SDWebImageCompat.m */, - D7F1314060E559C8947FF2156F1A92FC /* SDWebImageDecoder.h */, - FCC7CD02F4721E0FC8931E96B16AB368 /* SDWebImageDecoder.m */, - 01F7F0FD5C1DD4A57E10338DECBE08BF /* SDWebImageDownloader.h */, - 6B14D99E3A060C4422D52E1B43DF44C1 /* SDWebImageDownloader.m */, - A4EB749E8B64FB36F3E2A229C14D3E17 /* SDWebImageDownloaderOperation.h */, - F6D8E260B72CA343410625FD1A728004 /* SDWebImageDownloaderOperation.m */, - 6D35B8054C6A1FB85E1C8AF49DA754AB /* SDWebImageManager.h */, - 2745C6E9EBE97C845254602DC1592DF4 /* SDWebImageManager.m */, - 84CE5D699E3556BCEA5319CE02EC862B /* SDWebImageOperation.h */, - AF307A627BC5C545FD14AF15658B0A20 /* SDWebImagePrefetcher.h */, - 010A46F5A9D7559BB3CCF9ABDBCAFF24 /* SDWebImagePrefetcher.m */, - 640D011133223416ECD115481ABE11C6 /* UIButton+WebCache.h */, - 7FF2F911B4ACB0BBBE1355C44C19EBEB /* UIButton+WebCache.m */, - CD6EF89C9FB4BA901403ADC3AA39BEBF /* UIImage+GIF.h */, - AD6EDB41DF6DFD4BDC3AD9CA119C329E /* UIImage+GIF.m */, - ABE47F73E3A4F0D9C26747F2CCEB862D /* UIImage+MultiFormat.h */, - 5E6F2B93EA109FC734C799B37A5F2C65 /* UIImage+MultiFormat.m */, - DAA3558CAA80E807627A616811FA5BD6 /* UIImageView+HighlightedWebCache.h */, - A296555F1740CDDC85453F15267505CA /* UIImageView+HighlightedWebCache.m */, - A0B50EB1CF5F290CB62A27072E257F2B /* UIImageView+WebCache.h */, - F3AA6D231072BEA87D8361284B976373 /* UIImageView+WebCache.m */, - 012884903390C04A55B7E547DA2B34B5 /* UIView+WebCacheOperation.h */, - 7DAD08097357C3001C4E61ABB3FA5893 /* UIView+WebCacheOperation.m */, + E2A13FB89351C8CBD4E4D5F5253B714E /* Crashlytics */, + 531E03EB9BDA837BD15E5CFA33950AA3 /* Fabric */, + 331CA75B5D0363D2AF243E44D661F9A3 /* FileMD5Hash */, + 5427BBB5C33A290393604304A6049893 /* SDWebImage */, + 795312991DF0976E153D01C3DB2D7EFF /* SMCalloutView */, + A267B4F77F709351A47C49E0765B9726 /* SQLite.swift */, ); - name = Core; + name = Pods; sourceTree = ""; }; - C324234DA460FB6DAF1832F14EE1451F /* Products */ = { + E2A13FB89351C8CBD4E4D5F5253B714E /* Crashlytics */ = { isa = PBXGroup; children = ( - 64BBAED01933096F1844A17E2A6E9ECF /* FileMD5Hash.framework */, - 32CA5695E88A5637B79D100F29969924 /* Pods_Delta.framework */, - D08836B2071BB4727C71D229B96E924B /* SDWebImage.framework */, - 0B33A43387DF59869F2A6002F1DC3785 /* SQLite.framework */, + EA7149D3D08F2A6BC584BEBC314A9BFB /* ANSCompatibility.h */, + 4C4C366461DA3B92968A67361C700AB8 /* Answers.h */, + FC75BF94BACA3E271CFB55F764B1439B /* CLSAttributes.h */, + 99F8E44ACB5CF087E4BF8F904DE04F47 /* CLSLogging.h */, + FA9BCD1E0FC20F3166C12E76650B9006 /* CLSReport.h */, + 4E1FBC10E4C47720883970DAA89DFF1B /* CLSStackFrame.h */, + F9B93EC3996C232919BB4F98458C45D5 /* Crashlytics.h */, + EFCB351B3EEC448C22F06D7285DE95E6 /* Frameworks */, ); - name = Products; + name = Crashlytics; + path = Crashlytics; sourceTree = ""; }; - D4B2E49FCA447FD090EE210ED6CFDC21 /* Frameworks */ = { + EF5B18EEB9983E18AAF90F03F5AC0920 /* Support Files */ = { isa = PBXGroup; children = ( - 61A3B47FEA2DAE48B17702C888054593 /* Fabric.framework */, + 1F46051C1128C9358A3A710DEB82AA24 /* Info.plist */, + 9549FD9572AD09182CBFC5AF4C3806EC /* SDWebImage.modulemap */, + CC448D70D2D84A30A4A4D226A8ABD13F /* SDWebImage.xcconfig */, + 52C0F64FF5BD9D05D0DDD439AB4B4B4C /* SDWebImage-dummy.m */, + DDE976DADC01C9F233C73181B7C677FA /* SDWebImage-prefix.pch */, + 19644E545E27F0ABCAEA0D43C6DFB21E /* SDWebImage-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/SDWebImage"; + sourceTree = ""; + }; + EFCB351B3EEC448C22F06D7285DE95E6 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D8C077D2CD74FE7022E6E86BA03B9BAA /* Crashlytics.framework */, ); name = Frameworks; sourceTree = ""; @@ -499,45 +561,55 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 35D56EB4CB117295F095C80B2F024E20 /* Headers */ = { + 45644FD3D44A25933E73FC65465227F8 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 1B1088DAF42D74567A705DC440211D12 /* NSData+ImageContentType.h in Headers */, - 1C0F95DC71B64C451857A4C991BF2AF8 /* SDImageCache.h in Headers */, - 459009460BFBB3DBB4C9168143FC967E /* SDWebImage-umbrella.h in Headers */, - 2888ACC8836D2E79F2F341C32AB3E0B0 /* SDWebImageCompat.h in Headers */, - A7EF436BF7DF4C8640864FBA1BA94351 /* SDWebImageDecoder.h in Headers */, - 6C88898656689F997079D8C2E02D380B /* SDWebImageDownloader.h in Headers */, - 58C256076C467E9132B30FA203F4682E /* SDWebImageDownloaderOperation.h in Headers */, - 60C9DBA3EA5D0784AE9C8C87B51BBCF0 /* SDWebImageManager.h in Headers */, - 930D6D8D90701B4A6FD30E94CF42871B /* SDWebImageOperation.h in Headers */, - 85AC71E815A41D4B45A0EB55F9A5DB1E /* SDWebImagePrefetcher.h in Headers */, - 3CD0EE70D32733800E902E7C8AFEA79B /* UIButton+WebCache.h in Headers */, - CE103933627196D2BB63FCFB7DDDE1F0 /* UIImage+GIF.h in Headers */, - 7E7C64643C2C3AC5F7CBCC8E044801EF /* UIImage+MultiFormat.h in Headers */, - 291D6ECA35FE23753F9EFEDA8AB633FC /* UIImageView+HighlightedWebCache.h in Headers */, - F86C46E798AA77D74381F0A299724517 /* UIImageView+WebCache.h in Headers */, - 289C4C0E1B0E975621D177439BCF4B6F /* UIView+WebCacheOperation.h in Headers */, + AF71FA11F33D4FF8286DE4191247F4B9 /* NSData+ImageContentType.h in Headers */, + 307ACA884D90D1B1AF65D152027F8037 /* SDImageCache.h in Headers */, + DD3018D33ABEB0BAA61C562F8A5FFC45 /* SDWebImage-umbrella.h in Headers */, + 020AFCE363BBA923E907BD453C394A18 /* SDWebImageCompat.h in Headers */, + D76E41A83001A863D0EF9A3F0EC0F68B /* SDWebImageDecoder.h in Headers */, + 593AA045F16ABDD2E0C216A6693160A6 /* SDWebImageDownloader.h in Headers */, + 1FAD25073BF85238A82B39CF64208138 /* SDWebImageDownloaderOperation.h in Headers */, + 255360BAB2981F4F6C7C2ADFB034DD78 /* SDWebImageManager.h in Headers */, + A5F83FD5E39A40A303AEE42994F6BB2D /* SDWebImageOperation.h in Headers */, + B9AC8B5C153CD4028E20BDA493F3E8E9 /* SDWebImagePrefetcher.h in Headers */, + F01610EE244331A9AE359D92682841FB /* UIButton+WebCache.h in Headers */, + 19A8DB8810E10682948CBA8F1954F70E /* UIImage+GIF.h in Headers */, + 35ECA1266BE70763C47DB385321C8BDA /* UIImage+MultiFormat.h in Headers */, + 3EEAE0A72D5F8D0397B9DF878F9ABE98 /* UIImageView+HighlightedWebCache.h in Headers */, + E282C5080C3257C180B32B1F15F2842E /* UIImageView+WebCache.h in Headers */, + FC2D34D5B376D1F700CAFB0E04439235 /* UIView+WebCacheOperation.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - 5357A79BD0A1FE37AA0F4EE4EE9D05A5 /* Headers */ = { + 60803EF6FD8B9CEB9F583958E5B9C104 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 92C60A4E3797D69E6A7725B12E25C0D0 /* fts3_tokenizer.h in Headers */, - 5172EB82F181CD5C6058720F1EDBFFBA /* SQLite-Bridging.h in Headers */, - EA47189A2ADA7ABA3CAD4DAA9C862095 /* SQLite.h in Headers */, - F713228AE3D00F1C478CF62077F73AD7 /* SQLite.swift-umbrella.h in Headers */, + 8288FE73D4A817A73306848AF872DD3B /* SMCalloutView-umbrella.h in Headers */, + 0E8A3312FC090BE373D8B2DC9F33355C /* SMCalloutView.h in Headers */, + A41E5A0EF327ED9DF2D2866EF78F30A5 /* SMClassicCalloutView.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - EB96366D2C78C813C41EBAEF56FC0ED9 /* Headers */ = { + 8FBE883C1E351BF2AB6A893697981986 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 7784F558B74616E8DC1818DA0A0532BC /* Pods-Delta-umbrella.h in Headers */, + E4A2641C95DDD1AEE0BA851321A07FC8 /* Pods-Delta-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9E79C31AF032218761B7231BED8BA825 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 05585238F98FFE793DC0D1BA800C0D27 /* fts3_tokenizer.h in Headers */, + 20A087C33B817D962690FDC7E894405A /* SQLite-Bridging.h in Headers */, + A8274F6E16ECE48FB9139B8456A31201 /* SQLite.h in Headers */, + 8F7D92A4E63CC4056DFD5C0B1FD14910 /* SQLite.swift-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -553,24 +625,42 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 3E23F405271B35BEEA87F9840F74A510 /* Pods-Delta */ = { + 4B110CBCF3EEB0093F08DE352A1B92DA /* Pods-Delta */ = { isa = PBXNativeTarget; - buildConfigurationList = 0ABB0BB9AFF3C8D8FF7C2460E438B5E6 /* Build configuration list for PBXNativeTarget "Pods-Delta" */; + buildConfigurationList = 8CEDF6F3DB0895E0DA8B67EF2A37C22C /* Build configuration list for PBXNativeTarget "Pods-Delta" */; buildPhases = ( - 4B8CABDD309337BA47058081211D728F /* Sources */, - 54F1511A803376CB9F7035A4D9F764D3 /* Frameworks */, - EB96366D2C78C813C41EBAEF56FC0ED9 /* Headers */, + A8A7CB475AC069906F4B23BEB0BD4A7F /* Sources */, + 5C0DF94230C9EECDA7269ACD38F80BB8 /* Frameworks */, + 8FBE883C1E351BF2AB6A893697981986 /* Headers */, ); buildRules = ( ); dependencies = ( - 4DDDB8B816F29215470EC263CE338171 /* PBXTargetDependency */, - 32FA1882D4ABC28118B91D8E6A104BFB /* PBXTargetDependency */, - 0935BBD3CFD2E9F741AC2D7E88FF5501 /* PBXTargetDependency */, + 29BDFC0FDC07E71DABA85606ECDCDFD4 /* PBXTargetDependency */, + C658BFD1115AABC95D34853360A10A3D /* PBXTargetDependency */, + 35ED1E44B53F73C54B11C67782175716 /* PBXTargetDependency */, + 7912D2146AA8F4861919949C710FE08B /* PBXTargetDependency */, ); name = "Pods-Delta"; productName = "Pods-Delta"; - productReference = 32CA5695E88A5637B79D100F29969924 /* Pods_Delta.framework */; + productReference = FA5CE005707B6583BF9CE4DF86B180DC /* Pods_Delta.framework */; + productType = "com.apple.product-type.framework"; + }; + 5A0A16E27351F849E411E94C505CF452 /* SMCalloutView */ = { + isa = PBXNativeTarget; + buildConfigurationList = F8D4561891ACE1BC67CEB8D0C6F063E4 /* Build configuration list for PBXNativeTarget "SMCalloutView" */; + buildPhases = ( + 83F4AE4AB580D4EFA51C6D39F76BD923 /* Sources */, + 98F7206242604EADE5687F25134FD6E4 /* Frameworks */, + 60803EF6FD8B9CEB9F583958E5B9C104 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SMCalloutView; + productName = SMCalloutView; + productReference = 0BC95251B8ED1E506925B002BC5B1352 /* SMCalloutView.framework */; productType = "com.apple.product-type.framework"; }; 924057B2A88FC4B5526EC3FC7483ABE2 /* FileMD5Hash */ = { @@ -587,33 +677,16 @@ ); name = FileMD5Hash; productName = FileMD5Hash; - productReference = 64BBAED01933096F1844A17E2A6E9ECF /* FileMD5Hash.framework */; + productReference = 0159C36B78547E23EBA1867CAE65F002 /* FileMD5Hash.framework */; productType = "com.apple.product-type.framework"; }; - 95AEAD50DEA1563D4D1E2AD6EEE0E7B4 /* SDWebImage */ = { + D71D7949D6292CD21BE206D00103E682 /* SQLite.swift */ = { isa = PBXNativeTarget; - buildConfigurationList = 533175F905F937DF358073A42B67A5AA /* Build configuration list for PBXNativeTarget "SDWebImage" */; + buildConfigurationList = 668A24D62570C0D022FAD98278F67B72 /* Build configuration list for PBXNativeTarget "SQLite.swift" */; buildPhases = ( - 029BC4D3B4B34C75603230D495FF2FE6 /* Sources */, - 5DA87AB35B47EC77EC2088FBAF257BF6 /* Frameworks */, - 35D56EB4CB117295F095C80B2F024E20 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SDWebImage; - productName = SDWebImage; - productReference = D08836B2071BB4727C71D229B96E924B /* SDWebImage.framework */; - productType = "com.apple.product-type.framework"; - }; - D88F755329BB917F99DFC5405AC691FE /* SQLite.swift */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9679E283619E0024B3156EB387DDCBDE /* Build configuration list for PBXNativeTarget "SQLite.swift" */; - buildPhases = ( - A17AC6BBAD5FB70B85220CE98AEA2BD0 /* Sources */, - DA6FF3BA4FD643976251EC15FE2B2DDE /* Frameworks */, - 5357A79BD0A1FE37AA0F4EE4EE9D05A5 /* Headers */, + B722D46C99854F66A3C53AFC7A1D7F65 /* Sources */, + 6A87A94DB2110DBC645F09B6863C840A /* Frameworks */, + 9E79C31AF032218761B7231BED8BA825 /* Headers */, ); buildRules = ( ); @@ -621,7 +694,24 @@ ); name = SQLite.swift; productName = SQLite.swift; - productReference = 0B33A43387DF59869F2A6002F1DC3785 /* SQLite.framework */; + productReference = ACDD71A4691EF17778DC6EACBDAC34F1 /* SQLite.framework */; + productType = "com.apple.product-type.framework"; + }; + E02CAC9BD02FC53AAA763EA4830E4884 /* SDWebImage */ = { + isa = PBXNativeTarget; + buildConfigurationList = 336350D22A1C45232C1FDF436E1FEBA2 /* Build configuration list for PBXNativeTarget "SDWebImage" */; + buildPhases = ( + AABCA925A95FAE4250B2D9206D3D0081 /* Sources */, + D97354725A51F45FDD2257F6907CC168 /* Frameworks */, + 45644FD3D44A25933E73FC65465227F8 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SDWebImage; + productName = SDWebImage; + productReference = 16C12BA1CDC4BAA71A94C08D894DAE28 /* SDWebImage.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ @@ -641,73 +731,84 @@ en, ); mainGroup = 7DB346D0F39D3F0E887471402A8071AB; - productRefGroup = C324234DA460FB6DAF1832F14EE1451F /* Products */; + productRefGroup = 6E588658A8888B4B213D36BBF2905D46 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 924057B2A88FC4B5526EC3FC7483ABE2 /* FileMD5Hash */, - 3E23F405271B35BEEA87F9840F74A510 /* Pods-Delta */, - 95AEAD50DEA1563D4D1E2AD6EEE0E7B4 /* SDWebImage */, - D88F755329BB917F99DFC5405AC691FE /* SQLite.swift */, + 4B110CBCF3EEB0093F08DE352A1B92DA /* Pods-Delta */, + E02CAC9BD02FC53AAA763EA4830E4884 /* SDWebImage */, + 5A0A16E27351F849E411E94C505CF452 /* SMCalloutView */, + D71D7949D6292CD21BE206D00103E682 /* SQLite.swift */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 029BC4D3B4B34C75603230D495FF2FE6 /* Sources */ = { + 83F4AE4AB580D4EFA51C6D39F76BD923 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - BCDE9C9E8DDB9FD7F9F0F68200854276 /* NSData+ImageContentType.m in Sources */, - FEE67933F477210286CDEC86E60D32FF /* SDImageCache.m in Sources */, - 662C18FEA4DFF9970E8D028B281D97EA /* SDWebImage-dummy.m in Sources */, - D1EC729542506D0FF0FEAFC10E544BDC /* SDWebImageCompat.m in Sources */, - 32649919900BFE14972CB170A11E7A30 /* SDWebImageDecoder.m in Sources */, - 7487C10F58C60552A3B84C47EF4AABB5 /* SDWebImageDownloader.m in Sources */, - 843BDA3C40997300E0B3CB9E27043997 /* SDWebImageDownloaderOperation.m in Sources */, - F97431F8AA6A848ACA072E9DB7DCF5DF /* SDWebImageManager.m in Sources */, - D7570BC6C11012C5F53C53ABF8187CC6 /* SDWebImagePrefetcher.m in Sources */, - C0D6EE693288E4A34090518CEE18269F /* UIButton+WebCache.m in Sources */, - A66ECB0C1037DD2A24411DF60C9362AE /* UIImage+GIF.m in Sources */, - 6A00465C6CF90CE73C984F03572BE9C3 /* UIImage+MultiFormat.m in Sources */, - E8166EA34E4BEF58C5583C06CFFB0971 /* UIImageView+HighlightedWebCache.m in Sources */, - 71A419BAB91B0BECA6617C071891BF3C /* UIImageView+WebCache.m in Sources */, - A66BC5F91E9B66C05262C55BABAA0421 /* UIView+WebCacheOperation.m in Sources */, + 29D38081CE6E0C1DC7B78CB2467733EE /* SMCalloutView-dummy.m in Sources */, + 3BF50196E73DD51E6A1152973DFC27DD /* SMCalloutView.m in Sources */, + 29B4C7EBC553B1A96DDE7199EF7EB78A /* SMClassicCalloutView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 4B8CABDD309337BA47058081211D728F /* Sources */ = { + A8A7CB475AC069906F4B23BEB0BD4A7F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 7CBFCCC7367FCCF9D53FBFA8ED86BDD7 /* Pods-Delta-dummy.m in Sources */, + 0E95FFC222F9730AB5A2FA648F3DC10B /* Pods-Delta-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - A17AC6BBAD5FB70B85220CE98AEA2BD0 /* Sources */ = { + AABCA925A95FAE4250B2D9206D3D0081 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - B4D2E6BDA66762C41461DE1466567A22 /* AggregateFunctions.swift in Sources */, - A3C78AD9387EE296772B1B4031290DE9 /* Blob.swift in Sources */, - EAF8AC345B2B68E07E239E83AACF81E3 /* Collation.swift in Sources */, - 679DC0A54440ACE06C668426D960434B /* Connection.swift in Sources */, - E376FD7DF6990EB5D6059FF86AA392DD /* CoreFunctions.swift in Sources */, - EEF3F3825344DF5B3B1F91C8B3D92F81 /* CustomFunctions.swift in Sources */, - 6B70676C9CD3E65704CF5F345A58D7D8 /* Expression.swift in Sources */, - 80C66AC9B65D7A9E73EAF52953078A80 /* Foundation.swift in Sources */, - 098DD319E9D5AE3C4B413F1DCB7245E5 /* FTS4.swift in Sources */, - C3351D1B55FD32BBAD9B3335713FBB37 /* FTS5.swift in Sources */, - 81EA3C6ADBF7CCBC1711693AD8966D30 /* Helpers.swift in Sources */, - 4A2DCD3F0F0A15427A7008B45E0D3463 /* Operators.swift in Sources */, - C36994840D82BF702EC602A8DEC63223 /* Query.swift in Sources */, - E5102C928DC86E24E1FA70862A698132 /* RTree.swift in Sources */, - A5E0B4C7414F681B71DE66C07F4628C4 /* Schema.swift in Sources */, - 59757ED380B9FD2D3529CC01940ABC17 /* Setter.swift in Sources */, - 12CF79798B69B43D77D12724505829EB /* SQLite-Bridging.m in Sources */, - 9A73EA1D60A6932BDA2B033258B82247 /* SQLite.swift-dummy.m in Sources */, - F70F77BB9BD4B473EF5731A958F6CFB4 /* Statement.swift in Sources */, - A215B295B907F3FC375FFA644649A845 /* Value.swift in Sources */, + 67A9DED3A799C2C1B3190757AF74C869 /* NSData+ImageContentType.m in Sources */, + 53A1E27B96743AF1526979D7C407B36E /* SDImageCache.m in Sources */, + BD93645C73A232461BAFDCD2D583A48F /* SDWebImage-dummy.m in Sources */, + D47F030F3EE8210B84E275A72194BD50 /* SDWebImageCompat.m in Sources */, + 867ED479D87B069987F16CC84F1CB314 /* SDWebImageDecoder.m in Sources */, + D1B81917966545E8201CA9A7C53EAD86 /* SDWebImageDownloader.m in Sources */, + CB0C7E4A7184D8CB11F07ABB7E01BCBF /* SDWebImageDownloaderOperation.m in Sources */, + BB19B505BC3000C14CD0C6539F716F6F /* SDWebImageManager.m in Sources */, + 3B7E86A00F8C6E8F5A351516BDFC6E0A /* SDWebImagePrefetcher.m in Sources */, + 34F15EDD4167886716DE13EF3DA61525 /* UIButton+WebCache.m in Sources */, + BACF769130EA8F084781334E3F5487D6 /* UIImage+GIF.m in Sources */, + 01F6FD7829922FFEDBA0AC937221139D /* UIImage+MultiFormat.m in Sources */, + 7E1E4E7C559B3DCBC6FB1E3F91303A61 /* UIImageView+HighlightedWebCache.m in Sources */, + B4FF0763F545E55DDF9FB358526B21C5 /* UIImageView+WebCache.m in Sources */, + 4BFD33775F72F952206DA9101BA849A2 /* UIView+WebCacheOperation.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B722D46C99854F66A3C53AFC7A1D7F65 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D1AB6379EC7678A60E7A342E19CD7463 /* AggregateFunctions.swift in Sources */, + AB4F3A463C806CFD7BD412DC96CCA6FF /* Blob.swift in Sources */, + FD11B32C2CBEDD81033179121AAB5D2D /* Collation.swift in Sources */, + BC7F01C05460B87B4BD3597D8CFEDDD0 /* Connection.swift in Sources */, + 7BC82A3FB797473493834376FB76E54E /* CoreFunctions.swift in Sources */, + 14D45BB06714ADAB897AC0F9F5DEEB35 /* CustomFunctions.swift in Sources */, + B5C757D4F5CE144EBC972BC0EDA42EBC /* Expression.swift in Sources */, + 1C5A988FA0C3F4E0F3D81AC3C597B9E8 /* Foundation.swift in Sources */, + 483BC893AE648B89F28763CC2FE1932A /* FTS4.swift in Sources */, + FDEAC6DF3D7044CA7FDD15A185183C2C /* FTS5.swift in Sources */, + 0A108DF7E6F55085A67FC6E0FF9D597B /* Helpers.swift in Sources */, + D5F611A196AB19B6B27BC91E0F7CDF98 /* Operators.swift in Sources */, + DC0D674B7D20F83A7A5BAEEE4F00AFB5 /* Query.swift in Sources */, + 5EBA645F49A7944F9D5DE1DE7214B16C /* RTree.swift in Sources */, + 405F2E285A1E5033E75EA989DCE7F1BD /* Schema.swift in Sources */, + 69E9B37E0394A6C87B37648633198916 /* Setter.swift in Sources */, + E70CE29F92FC143D25EBAB0AA0FF7847 /* SQLite-Bridging.m in Sources */, + 02A3EAB09395DB7996C6A2D6FFEEA541 /* SQLite.swift-dummy.m in Sources */, + F76BA2CF262298B5E751146776A25CB2 /* Statement.swift in Sources */, + 65C3F0B49DCF090CFC1A57B581B7D5EE /* Value.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -723,30 +824,69 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 0935BBD3CFD2E9F741AC2D7E88FF5501 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = SQLite.swift; - target = D88F755329BB917F99DFC5405AC691FE /* SQLite.swift */; - targetProxy = 43751C8F4A1E0FED8A513B6C736B2141 /* PBXContainerItemProxy */; - }; - 32FA1882D4ABC28118B91D8E6A104BFB /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = SDWebImage; - target = 95AEAD50DEA1563D4D1E2AD6EEE0E7B4 /* SDWebImage */; - targetProxy = B1786652CDC10C9D41868B80152892A5 /* PBXContainerItemProxy */; - }; - 4DDDB8B816F29215470EC263CE338171 /* PBXTargetDependency */ = { + 29BDFC0FDC07E71DABA85606ECDCDFD4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = FileMD5Hash; target = 924057B2A88FC4B5526EC3FC7483ABE2 /* FileMD5Hash */; - targetProxy = F1D70524142DB2A888CA1F6E3F0F67CC /* PBXContainerItemProxy */; + targetProxy = 0E57566421DC7C04ED10FBFF02AE3217 /* PBXContainerItemProxy */; + }; + 35ED1E44B53F73C54B11C67782175716 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SMCalloutView; + target = 5A0A16E27351F849E411E94C505CF452 /* SMCalloutView */; + targetProxy = 7713FF1D874368FBE2D22D4E4CB7C6A7 /* PBXContainerItemProxy */; + }; + 7912D2146AA8F4861919949C710FE08B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SQLite.swift; + target = D71D7949D6292CD21BE206D00103E682 /* SQLite.swift */; + targetProxy = 3AAE57E02BD6B50C58159D299DCA0C4F /* PBXContainerItemProxy */; + }; + C658BFD1115AABC95D34853360A10A3D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SDWebImage; + target = E02CAC9BD02FC53AAA763EA4830E4884 /* SDWebImage */; + targetProxy = 387F41711D87C3D2C8716FF754189765 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 34CC1AA0F2C62D3C5C3A2AEF38F2FE78 /* Release */ = { + 0D2198DAA52D58080E95DBD3D8992214 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 31B7E048CEBB667B0795D7399EA829AF /* SDWebImage.xcconfig */; + baseConfigurationReference = 061C525038BE58FCE9A6013CBA4162B5 /* SMCalloutView.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/SMCalloutView/SMCalloutView-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SMCalloutView/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SMCalloutView/SMCalloutView.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = SMCalloutView; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 20BA7269FACC47ABAD2D3CC89BC89EC6 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EA65B5484E3BB3284577BD4EA4FA7147 /* Pods-Delta.release.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; @@ -760,16 +900,21 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; - GCC_PREFIX_HEADER = "Target Support Files/SDWebImage/SDWebImage-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/SDWebImage/Info.plist"; + INFOPLIST_FILE = "Target Support Files/Pods-Delta/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/SDWebImage/SDWebImage.modulemap"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Delta/Pods-Delta.modulemap"; MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = SDWebImage; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Delta; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -777,6 +922,75 @@ }; name = Release; }; + 32CD4441BC4925087C9B9D2D64782195 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2FD50D8325E1E8D2B0953062797E6E02 /* SQLite.swift.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/SQLite.swift/SQLite.swift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SQLite.swift/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SQLite.swift/SQLite.swift.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = SQLite; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 435F325F37C4CB44C79CC5FF7289A36D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2FD50D8325E1E8D2B0953062797E6E02 /* SQLite.swift.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/SQLite.swift/SQLite.swift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SQLite.swift/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SQLite.swift/SQLite.swift.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = SQLite; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; 643C76AA582046977B7877822ED7A258 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -825,48 +1039,9 @@ }; name = Debug; }; - 75EE5B0ED6DB7C6D167C2008C7D4D49C /* Debug */ = { + 90407854EE6F767B6B23052DB718601F /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1C3BA8511D0F025064897F6EC408296A /* Pods-Delta.debug.xcconfig */; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "Target Support Files/Pods-Delta/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACH_O_TYPE = staticlib; - MODULEMAP_FILE = "Target Support Files/Pods-Delta/Pods-Delta.modulemap"; - MTL_ENABLE_DEBUG_INFO = YES; - OTHER_LDFLAGS = ""; - OTHER_LIBTOOLFLAGS = ""; - PODS_ROOT = "$(SRCROOT)"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = Pods_Delta; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 7CB79771FB206E08213038425109B42C /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = EA65B5484E3BB3284577BD4EA4FA7147 /* Pods-Delta.release.xcconfig */; + baseConfigurationReference = 061C525038BE58FCE9A6013CBA4162B5 /* SMCalloutView.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; @@ -880,21 +1055,49 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "Target Support Files/Pods-Delta/Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/SMCalloutView/SMCalloutView-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SMCalloutView/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACH_O_TYPE = staticlib; - MODULEMAP_FILE = "Target Support Files/Pods-Delta/Pods-Delta.modulemap"; + MODULEMAP_FILE = "Target Support Files/SMCalloutView/SMCalloutView.modulemap"; MTL_ENABLE_DEBUG_INFO = NO; - OTHER_LDFLAGS = ""; - OTHER_LIBTOOLFLAGS = ""; - PODS_ROOT = "$(SRCROOT)"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; - PRODUCT_NAME = Pods_Delta; + PRODUCT_NAME = SMCalloutView; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 94B2E36B9D50BB1F23C442EECC3A98DE /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CC448D70D2D84A30A4A4D226A8ABD13F /* SDWebImage.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/SDWebImage/SDWebImage-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SDWebImage/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SDWebImage/SDWebImage.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = SDWebImage; SDKROOT = iphoneos; SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -904,7 +1107,7 @@ }; 9ED0ADE0EA3D1E3B4EA7EFBE25BB4D6F /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CB5685E217F7B2F7EDAAC619C783CDDA /* FileMD5Hash.xcconfig */; + baseConfigurationReference = DFB799765277CB092B656E76446C5A75 /* FileMD5Hash.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; @@ -935,75 +1138,6 @@ }; name = Release; }; - B284F3DC897E0D103E422DDAA04F371D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7E0880D76FFD4DB866FA61B3BBE9D8EE /* SQLite.swift.xcconfig */; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREFIX_HEADER = "Target Support Files/SQLite.swift/SQLite.swift-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/SQLite.swift/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/SQLite.swift/SQLite.swift.modulemap"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_NAME = SQLite; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - B848EC96B1CE2C5324C340E1F1935FD8 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7E0880D76FFD4DB866FA61B3BBE9D8EE /* SQLite.swift.xcconfig */; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREFIX_HEADER = "Target Support Files/SQLite.swift/SQLite.swift-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/SQLite.swift/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/SQLite.swift/SQLite.swift.modulemap"; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = SQLite; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; C03B8870130C98D1B02B59D003687524 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1048,42 +1182,9 @@ }; name = Release; }; - D49B8E408047BA5314BE2727D48E1834 /* Debug */ = { + C955FC7239704D1450516B7FD0992E76 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CB5685E217F7B2F7EDAAC619C783CDDA /* FileMD5Hash.xcconfig */; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREFIX_HEADER = "Target Support Files/FileMD5Hash/FileMD5Hash-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/FileMD5Hash/Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MODULEMAP_FILE = "Target Support Files/FileMD5Hash/FileMD5Hash.modulemap"; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_NAME = FileMD5Hash; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - FF2643C8017F1A3A64AA8C00C06221D7 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 31B7E048CEBB667B0795D7399EA829AF /* SDWebImage.xcconfig */; + baseConfigurationReference = CC448D70D2D84A30A4A4D226A8ABD13F /* SDWebImage.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; @@ -1114,6 +1215,78 @@ }; name = Debug; }; + D49B8E408047BA5314BE2727D48E1834 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DFB799765277CB092B656E76446C5A75 /* FileMD5Hash.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/FileMD5Hash/FileMD5Hash-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/FileMD5Hash/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/FileMD5Hash/FileMD5Hash.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = FileMD5Hash; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + DC6449F204C483A3EC3E347DD20187E8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1C3BA8511D0F025064897F6EC408296A /* Pods-Delta.debug.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Target Support Files/Pods-Delta/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Delta/Pods-Delta.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Delta; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1126,15 +1299,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 0ABB0BB9AFF3C8D8FF7C2460E438B5E6 /* Build configuration list for PBXNativeTarget "Pods-Delta" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 75EE5B0ED6DB7C6D167C2008C7D4D49C /* Debug */, - 7CB79771FB206E08213038425109B42C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1144,20 +1308,38 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 533175F905F937DF358073A42B67A5AA /* Build configuration list for PBXNativeTarget "SDWebImage" */ = { + 336350D22A1C45232C1FDF436E1FEBA2 /* Build configuration list for PBXNativeTarget "SDWebImage" */ = { isa = XCConfigurationList; buildConfigurations = ( - FF2643C8017F1A3A64AA8C00C06221D7 /* Debug */, - 34CC1AA0F2C62D3C5C3A2AEF38F2FE78 /* Release */, + C955FC7239704D1450516B7FD0992E76 /* Debug */, + 94B2E36B9D50BB1F23C442EECC3A98DE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 9679E283619E0024B3156EB387DDCBDE /* Build configuration list for PBXNativeTarget "SQLite.swift" */ = { + 668A24D62570C0D022FAD98278F67B72 /* Build configuration list for PBXNativeTarget "SQLite.swift" */ = { isa = XCConfigurationList; buildConfigurations = ( - B284F3DC897E0D103E422DDAA04F371D /* Debug */, - B848EC96B1CE2C5324C340E1F1935FD8 /* Release */, + 435F325F37C4CB44C79CC5FF7289A36D /* Debug */, + 32CD4441BC4925087C9B9D2D64782195 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8CEDF6F3DB0895E0DA8B67EF2A37C22C /* Build configuration list for PBXNativeTarget "Pods-Delta" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DC6449F204C483A3EC3E347DD20187E8 /* Debug */, + 20BA7269FACC47ABAD2D3CC89BC89EC6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F8D4561891ACE1BC67CEB8D0C6F063E4 /* Build configuration list for PBXNativeTarget "SMCalloutView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0D2198DAA52D58080E95DBD3D8992214 /* Debug */, + 90407854EE6F767B6B23052DB718601F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Pods/SMCalloutView/LICENSE b/Pods/SMCalloutView/LICENSE new file mode 100644 index 0000000..2bb9ad2 --- /dev/null +++ b/Pods/SMCalloutView/LICENSE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/Pods/SMCalloutView/README.md b/Pods/SMCalloutView/README.md new file mode 100644 index 0000000..4ce2939 --- /dev/null +++ b/Pods/SMCalloutView/README.md @@ -0,0 +1,99 @@ +![Example Screenshot](SampleAssets/CalloutScreenshot.png) + + +Overview +-------- + +SMCalloutView aims to be an exact replica of the private UICalloutView system +control. + +We all love those "bubbles" you get when clicking pins in MKMapView. But +sadly, it's impossible to present this bubble-style "Callout" UI anywhere +outside MKMapView. Phooey! So this class _painstakingly_ recreates this handy +control for your pleasure. + + +Usage +----- + +To use SMCalloutView in your own projects, simply copy the files +`SMCalloutView.h` and `SMCalloutView.m`. + +SMCalloutView, by default, will render in the new style introduced with +iOS 7. If you need the old style, simply include `SMClassicCalloutView.h` +and `SMClassicCalloutView.m` in your project as well. There is a special +class constructor, `+[SMCalloutView platformCalloutView]` which will +automatically select the appropriate callout class for the current platform. + +The comments in `SMCalloutView.h` do a lot of explaining on how to use the +class, but the main function you'll need is `presentCalloutFromRect:`. You'll +specify the view you'd like to add the callout to, as well as the rect +defining the "target" that the popup should point at. The target rect should +be _in the coordinate system of the target view_ (just like the similarly- +named `UIPopover` method). Most likely this will be `target.frame` if you're +adding the callout view as a sibling of the target view, or it would be +`target.bounds` if you're adding the callout view to the target itself. + +You can study the included project's UIViewController subclasses for a working +example. + + +Questions +--------- + +#### How do I change the height of the callout? + +If you use only the `title/titleView/subtitle/subtitleView` properties, the +callout will always be the "system standard" height. If you assign the +`contentView` property however, then the callout will size to fit the +`contentView` and the other properties are ignored. + + [#29]: https://github.com/nfarina/calloutview/issues/29 + + +#### Can I customize the background graphics? + +Yes, the callout background is an instance of `SMCalloutBackgroundView`. You +can set your own custom `View` subclass to be the background, or you can use +one of the built-in subclasses: + + - `SMCalloutMaskedBackgroundView` renders an iOS-7 style background. + + - `SMCalloutImageBackgroundView` lets you specify each of the image + "fragments" that make up a horizontally-stretchable background. + + - `SMCalloutDrawnBackgroundView` draws the background at any size using + CoreGraphics methods. You can copy the `-drawRect` method and change the + parameters to suit your needs. + + +#### Can I use the callout with the Google Maps iOS SDK? + +Check out [ryanmaxwell's demo project][googlemaps] for an example of one way +to do this. ([More discussion on this topic][#25]) + + [googlemaps]: https://github.com/ryanmaxwell/GoogleMapsCalloutView + [#25]: https://github.com/nfarina/calloutview/issues/25 + + +#### Have you recreated more of MapKit? + +Nope, but other intrepid coders have! + +- For an awesome replacement of the pulsing blue "Current Location" dot, check + out [Sam Vermette's SVPulsingAnnotationView][dot]. + +- And for the outdoor map data and tiles themselves, check out [Mapbox's iOS + SDK][mapbox], a complete open-source solution for custom maps. They even use + `SMCalloutView` out of the box! + + [dot]: https://github.com/samvermette/SVPulsingAnnotationView + [mapbox]: https://www.mapbox.com/mobile/ + + +More Info +--------- + +You can read more info if you wish in the [blog post][]. + + [blog post]: http://nfarina.com/post/78014139253/smcalloutview-for-ios-7 diff --git a/Pods/SMCalloutView/SMCalloutView.h b/Pods/SMCalloutView/SMCalloutView.h new file mode 100755 index 0000000..96fd744 --- /dev/null +++ b/Pods/SMCalloutView/SMCalloutView.h @@ -0,0 +1,200 @@ +#import +#import + +/* + +SMCalloutView +------------- +Created by Nick Farina (nfarina@gmail.com) +Version 2.1.5 + +*/ + +/// options for which directions the callout is allowed to "point" in. +typedef NS_OPTIONS(NSUInteger, SMCalloutArrowDirection) { + SMCalloutArrowDirectionUp = 1 << 0, + SMCalloutArrowDirectionDown = 1 << 1, + SMCalloutArrowDirectionAny = SMCalloutArrowDirectionUp | SMCalloutArrowDirectionDown +}; + +/// options for the callout present/dismiss animation +typedef NS_ENUM(NSInteger, SMCalloutAnimation) { + /// the "bounce" animation we all know and love from @c UIAlertView + SMCalloutAnimationBounce, + /// a simple fade in or out + SMCalloutAnimationFade, + /// grow or shrink linearly, like in the iPad Calendar app + SMCalloutAnimationStretch +}; + +NS_ASSUME_NONNULL_BEGIN + +/// when delaying our popup in order to scroll content into view, you can use this amount to match the +/// animation duration of UIScrollView when using @c -setContentOffset:animated. +extern NSTimeInterval const kSMCalloutViewRepositionDelayForUIScrollView; + +@protocol SMCalloutViewDelegate; +@class SMCalloutBackgroundView; + +// +// Callout view. +// + +@interface SMCalloutView : UIView + +@property (nonatomic, weak, nullable) id delegate; +/// title/titleView relationship mimics UINavigationBar. +@property (nonatomic, copy, nullable) NSString *title; +@property (nonatomic, copy, nullable) NSString *subtitle; + +/// Left accessory view for the call out +@property (nonatomic, strong, nullable) UIView *leftAccessoryView; +/// Right accessoty view for the call out +@property (nonatomic, strong, nullable) UIView *rightAccessoryView; +/// Default @c SMCalloutArrowDirectionDown +@property (nonatomic, assign) SMCalloutArrowDirection permittedArrowDirection; +/// The current arrow direction +@property (nonatomic, readonly) SMCalloutArrowDirection currentArrowDirection; +/// if the @c UIView you're constraining to has portions that are overlapped by nav bar, tab bar, etc. you'll need to tell us those insets. +@property (nonatomic, assign) UIEdgeInsets constrainedInsets; +/// default is @c SMCalloutMaskedBackgroundView, or @c SMCalloutDrawnBackgroundView when using @c SMClassicCalloutView +@property (nonatomic, strong) SMCalloutBackgroundView *backgroundView; + +/** + @brief Custom title view. + + @disucssion Keep in mind that @c SMCalloutView calls @c -sizeThatFits on titleView/subtitleView if defined, so your view + may be resized as a result of that (especially if you're using @c UILabel/UITextField). You may want to subclass and override @c -sizeThatFits, or just wrap your view in a "generic" @c UIView if you do not want it to be auto-sized. + + @warning If this is set, the respective @c title property will be ignored. + */ +@property (nonatomic, strong, nullable) UIView *titleView; + +/** + @brief Custom subtitle view. + + @discussion Keep in mind that @c SMCalloutView calls @c -sizeThatFits on subtitleView if defined, so your view + may be resized as a result of that (especially if you're using @c UILabel/UITextField). You may want to subclass and override @c -sizeThatFits, or just wrap your view in a "generic" @c UIView if you do not want it to be auto-sized. + + @warning If this is set, the respective @c subtitle property will be ignored. + */ +@property (nonatomic, strong, nullable) UIView *subtitleView; + +/// Custom "content" view that can be any width/height. If this is set, title/subtitle/titleView/subtitleView are all ignored. +@property (nonatomic, retain, nullable) UIView *contentView; + +/// Custom content view margin +@property (nonatomic, assign) UIEdgeInsets contentViewInset; + +/// calloutOffset is the offset in screen points from the top-middle of the target view, where the anchor of the callout should be shown. +@property (nonatomic, assign) CGPoint calloutOffset; + +/// default SMCalloutAnimationBounce, SMCalloutAnimationFade respectively +@property (nonatomic, assign) SMCalloutAnimation presentAnimation, dismissAnimation; + +/// Returns a new instance of SMCalloutView if running on iOS 7 or better, otherwise a new instance of SMClassicCalloutView if available. ++ (SMCalloutView *)platformCalloutView; + +/** + @brief Presents a callout view by adding it to "inView" and pointing at the given rect of inView's bounds. + + @discussion Constrains the callout to the bounds of the given view. Optionally scrolls the given rect into view (plus margins) + if @c -delegate is set and responds to @c -delayForRepositionWithSize. + + @param rect @c CGRect to present the view from + @param view view to 'constrain' the @c constrainedView to + @param constrainedView @c UIView to be constrainted in @c view + @param animated @c BOOL if presentation should be animated + */ +- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated; + +/** + @brief Present a callout layer in the `layer` and pointing at the given rect of the `layer` bounds + + @discussion Same as the view-based presentation, but inserts the callout into a CALayer hierarchy instead. + @note Be aware that you'll have to direct your own touches to any accessory views, since CALayer doesn't relay touch events. + + @param rect @c CGRect to present the view from + @param layer layer to 'constrain' the @c constrainedLayer to + @param constrainedLayer @c CALayer to be constrained in @c layer + @param animated @c BOOL if presentation should be animated + */ +- (void)presentCalloutFromRect:(CGRect)rect inLayer:(CALayer *)layer constrainedToLayer:(CALayer *)constrainedLayer animated:(BOOL)animated; + +/** + Dismiss the callout view + + @param animated @c BOOL if dismissal should be animated + */ +- (void)dismissCalloutAnimated:(BOOL)animated; + +/// For subclassers. You can override this method to provide your own custom animation for presenting/dismissing the callout. +- (CAAnimation *)animationWithType:(SMCalloutAnimation)type presenting:(BOOL)presenting; + +@end + +// +// Background view - default draws the iOS 7 system background style (translucent white with rounded arrow). +// + +/// Abstract base class +@interface SMCalloutBackgroundView : UIView +/// indicates where the tip of the arrow should be drawn, as a pixel offset +@property (nonatomic, assign) CGPoint arrowPoint; +/// will be set by the callout when the callout is in a highlighted state +@property (nonatomic, assign) BOOL highlighted; +/// returns an optional layer whose contents should mask the callout view's contents (not honored by @c SMClassicCalloutView ) +@property (nonatomic, assign) CALayer *contentMask; +/// height of the callout "arrow" +@property (nonatomic, assign) CGFloat anchorHeight; +/// the smallest possible distance from the edge of our control to the "tip" of the anchor, from either left or right +@property (nonatomic, assign) CGFloat anchorMargin; +@end + +/// Default for iOS 7, this reproduces the "masked" behavior of the iOS 7-style callout view. +/// Accessories are masked by the shape of the callout (including the arrow itself). +@interface SMCalloutMaskedBackgroundView : SMCalloutBackgroundView +@end + +// +// Delegate methods +// + +@protocol SMCalloutViewDelegate +@optional + +/// Controls whether the callout "highlights" when pressed. default YES. You must also respond to @c -calloutViewClicked below. +/// Not honored by @c SMClassicCalloutView. +- (BOOL)calloutViewShouldHighlight:(SMCalloutView *)calloutView; + +/// Called when the callout view is clicked. Not honored by @c SMClassicCalloutView. +- (void)calloutViewClicked:(SMCalloutView *)calloutView; + +/** + Called when the callout view detects that it will be outside the constrained view when it appears, + or if the target rect was already outside the constrained view. You can implement this selector + to respond to this situation by repositioning your content first in order to make everything visible. + The @c CGSize passed is the calculated offset necessary to make everything visible (plus a nice margin). + It expects you to return the amount of time you need to reposition things so the popup can be delayed. + Typically you would return @c kSMCalloutViewRepositionDelayForUIScrollView if you're repositioning by calling @c [UIScrollView @c setContentOffset:animated:]. + + @param calloutView the @c SMCalloutView to reposition + @param offset caluclated offset necessary to make everything visible + @returns @c NSTimeInterval to delay the repositioning + */ +- (NSTimeInterval)calloutView:(SMCalloutView *)calloutView delayForRepositionWithSize:(CGSize)offset; + +/// Called before the callout view appears on screen, or before the appearance animation will start. +- (void)calloutViewWillAppear:(SMCalloutView *)calloutView; + +/// Called after the callout view appears on screen, or after the appearance animation is complete. +- (void)calloutViewDidAppear:(SMCalloutView *)calloutView; + +/// Called before the callout view is removed from the screen, or before the disappearance animation is complete. +- (void)calloutViewWillDisappear:(SMCalloutView *)calloutView; + +/// Called after the callout view is removed from the screen, or after the disappearance animation is complete. +- (void)calloutViewDidDisappear:(SMCalloutView *)calloutView; + +NS_ASSUME_NONNULL_END +@end diff --git a/Pods/SMCalloutView/SMCalloutView.m b/Pods/SMCalloutView/SMCalloutView.m new file mode 100755 index 0000000..5943c50 --- /dev/null +++ b/Pods/SMCalloutView/SMCalloutView.m @@ -0,0 +1,859 @@ +#import "SMCalloutView.h" + +// +// UIView frame helpers - we do a lot of UIView frame fiddling in this class; these functions help keep things readable. +// + +@interface UIView (SMFrameAdditions) +@property (nonatomic, assign) CGPoint frameOrigin; +@property (nonatomic, assign) CGSize frameSize; +@property (nonatomic, assign) CGFloat frameX, frameY, frameWidth, frameHeight; // normal rect properties +@property (nonatomic, assign) CGFloat frameLeft, frameTop, frameRight, frameBottom; // these will stretch/shrink the rect +@end + +// +// Callout View. +// + +#define CALLOUT_DEFAULT_CONTAINER_HEIGHT 44 // height of just the main portion without arrow +#define CALLOUT_SUB_DEFAULT_CONTAINER_HEIGHT 52 // height of just the main portion without arrow (when subtitle is present) +#define CALLOUT_MIN_WIDTH 61 // minimum width of system callout +#define TITLE_HMARGIN 12 // the title/subtitle view's normal horizontal margin from the edges of our callout view or from the accessories +#define TITLE_TOP 11 // the top of the title view when no subtitle is present +#define TITLE_SUB_TOP 4 // the top of the title view when a subtitle IS present +#define TITLE_HEIGHT 21 // title height, fixed +#define SUBTITLE_TOP 28 // the top of the subtitle, when present +#define SUBTITLE_HEIGHT 15 // subtitle height, fixed +#define BETWEEN_ACCESSORIES_MARGIN 7 // margin between accessories when no title/subtitle is present +#define TOP_ANCHOR_MARGIN 13 // all the above measurements assume a bottom anchor! if we're pointing "up" we'll need to add this top margin to everything. +#define COMFORTABLE_MARGIN 10 // when we try to reposition content to be visible, we'll consider this margin around your target rect + +NSTimeInterval const kSMCalloutViewRepositionDelayForUIScrollView = 1.0/3.0; + +@interface SMCalloutView () +@property (nonatomic, strong) UIButton *containerView; // for masking and interaction +@property (nonatomic, strong) UILabel *titleLabel, *subtitleLabel; +@property (nonatomic, assign) SMCalloutArrowDirection currentArrowDirection; +@property (nonatomic, assign) BOOL popupCancelled; +@end + +@implementation SMCalloutView + ++ (SMCalloutView *)platformCalloutView { + + // if you haven't compiled SMClassicCalloutView into your app, then we can't possibly create an instance of it! + if (!NSClassFromString(@"SMClassicCalloutView")) + return [SMCalloutView new]; + + // ok we have both - so choose the best one based on current platform + if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) + return [SMCalloutView new]; // iOS 7+ + else + return [NSClassFromString(@"SMClassicCalloutView") new]; +} + +- (id)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.permittedArrowDirection = SMCalloutArrowDirectionDown; + self.presentAnimation = SMCalloutAnimationBounce; + self.dismissAnimation = SMCalloutAnimationFade; + self.backgroundColor = [UIColor clearColor]; + self.containerView = [UIButton new]; + self.containerView.isAccessibilityElement = NO; + self.isAccessibilityElement = NO; + self.contentViewInset = UIEdgeInsetsMake(12, 12, 12, 12); + + [self.containerView addTarget:self action:@selector(highlightIfNecessary) forControlEvents:UIControlEventTouchDown | UIControlEventTouchDragInside]; + [self.containerView addTarget:self action:@selector(unhighlightIfNecessary) forControlEvents:UIControlEventTouchDragOutside | UIControlEventTouchCancel | UIControlEventTouchUpOutside | UIControlEventTouchUpInside]; + [self.containerView addTarget:self action:@selector(calloutClicked) forControlEvents:UIControlEventTouchUpInside]; + } + return self; +} + +- (BOOL)supportsHighlighting { + if (![self.delegate respondsToSelector:@selector(calloutViewClicked:)]) + return NO; + if ([self.delegate respondsToSelector:@selector(calloutViewShouldHighlight:)]) + return [self.delegate calloutViewShouldHighlight:self]; + return YES; +} + +- (void)highlightIfNecessary { if (self.supportsHighlighting) self.backgroundView.highlighted = YES; } +- (void)unhighlightIfNecessary { if (self.supportsHighlighting) self.backgroundView.highlighted = NO; } + +- (void)calloutClicked { + if ([self.delegate respondsToSelector:@selector(calloutViewClicked:)]) + [self.delegate calloutViewClicked:self]; +} + +- (UIView *)titleViewOrDefault { + if (self.titleView) + // if you have a custom title view defined, return that. + return self.titleView; + else { + if (!self.titleLabel) { + // create a default titleView + self.titleLabel = [UILabel new]; + self.titleLabel.frameHeight = TITLE_HEIGHT; + self.titleLabel.opaque = NO; + self.titleLabel.backgroundColor = [UIColor clearColor]; + self.titleLabel.font = [UIFont systemFontOfSize:17]; + self.titleLabel.textColor = [UIColor blackColor]; + } + return self.titleLabel; + } +} + +- (UIView *)subtitleViewOrDefault { + if (self.subtitleView) + // if you have a custom subtitle view defined, return that. + return self.subtitleView; + else { + if (!self.subtitleLabel) { + // create a default subtitleView + self.subtitleLabel = [UILabel new]; + self.subtitleLabel.frameHeight = SUBTITLE_HEIGHT; + self.subtitleLabel.opaque = NO; + self.subtitleLabel.backgroundColor = [UIColor clearColor]; + self.subtitleLabel.font = [UIFont systemFontOfSize:12]; + self.subtitleLabel.textColor = [UIColor blackColor]; + } + return self.subtitleLabel; + } +} + +- (SMCalloutBackgroundView *)backgroundView { + // create our default background on first access only if it's nil, since you might have set your own background anyway. + return _backgroundView ? _backgroundView : (_backgroundView = [self defaultBackgroundView]); +} + +- (SMCalloutBackgroundView *)defaultBackgroundView { + return [SMCalloutMaskedBackgroundView new]; +} + +- (void)rebuildSubviews { + // remove and re-add our appropriate subviews in the appropriate order + [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + [self.containerView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + [self setNeedsDisplay]; + + [self addSubview:self.backgroundView]; + [self addSubview:self.containerView]; + + if (self.contentView) { + [self.containerView addSubview:self.contentView]; + } + else { + if (self.titleViewOrDefault) [self.containerView addSubview:self.titleViewOrDefault]; + if (self.subtitleViewOrDefault) [self.containerView addSubview:self.subtitleViewOrDefault]; + } + if (self.leftAccessoryView) [self.containerView addSubview:self.leftAccessoryView]; + if (self.rightAccessoryView) [self.containerView addSubview:self.rightAccessoryView]; +} + +// Accessory margins. Accessories are centered vertically when shorter +// than the callout, otherwise they grow from the upper corner. + +- (CGFloat)leftAccessoryVerticalMargin { + if (self.leftAccessoryView.frameHeight < self.calloutContainerHeight) + return roundf((self.calloutContainerHeight - self.leftAccessoryView.frameHeight) / 2); + else + return 0; +} + +- (CGFloat)leftAccessoryHorizontalMargin { + return fminf(self.leftAccessoryVerticalMargin, TITLE_HMARGIN); +} + +- (CGFloat)rightAccessoryVerticalMargin { + if (self.rightAccessoryView.frameHeight < self.calloutContainerHeight) + return roundf((self.calloutContainerHeight - self.rightAccessoryView.frameHeight) / 2); + else + return 0; +} + +- (CGFloat)rightAccessoryHorizontalMargin { + return fminf(self.rightAccessoryVerticalMargin, TITLE_HMARGIN); +} + +- (CGFloat)innerContentMarginLeft { + if (self.leftAccessoryView) + return self.leftAccessoryHorizontalMargin + self.leftAccessoryView.frameWidth + TITLE_HMARGIN; + else + return self.contentViewInset.left; +} + +- (CGFloat)innerContentMarginRight { + if (self.rightAccessoryView) + return self.rightAccessoryHorizontalMargin + self.rightAccessoryView.frameWidth + TITLE_HMARGIN; + else + return self.contentViewInset.right; +} + +- (CGFloat)calloutHeight { + return self.calloutContainerHeight + self.backgroundView.anchorHeight; +} + +- (CGFloat)calloutContainerHeight { + if (self.contentView) + return self.contentView.frameHeight + self.contentViewInset.bottom + self.contentViewInset.top; + else if (self.subtitleView || self.subtitle.length > 0) + return CALLOUT_SUB_DEFAULT_CONTAINER_HEIGHT; + else + return CALLOUT_DEFAULT_CONTAINER_HEIGHT; +} + +- (CGSize)sizeThatFits:(CGSize)size { + + // calculate how much non-negotiable space we need to reserve for margin and accessories + CGFloat margin = self.innerContentMarginLeft + self.innerContentMarginRight; + + // how much room is left for text? + CGFloat availableWidthForText = size.width - margin - 1; + + // no room for text? then we'll have to squeeze into the given size somehow. + if (availableWidthForText < 0) + availableWidthForText = 0; + + CGSize preferredTitleSize = [self.titleViewOrDefault sizeThatFits:CGSizeMake(availableWidthForText, TITLE_HEIGHT)]; + CGSize preferredSubtitleSize = [self.subtitleViewOrDefault sizeThatFits:CGSizeMake(availableWidthForText, SUBTITLE_HEIGHT)]; + + // total width we'd like + CGFloat preferredWidth; + + if (self.contentView) { + + // if we have a content view, then take our preferred size directly from that + preferredWidth = self.contentView.frameWidth + margin; + } + else if (preferredTitleSize.width >= 0.000001 || preferredSubtitleSize.width >= 0.000001) { + + // if we have a title or subtitle, then our assumed margins are valid, and we can apply them + preferredWidth = fmaxf(preferredTitleSize.width, preferredSubtitleSize.width) + margin; + } + else { + // ok we have no title or subtitle to speak of. In this case, the system callout would actually not display + // at all! But we can handle it. + preferredWidth = self.leftAccessoryView.frameWidth + self.rightAccessoryView.frameWidth + self.leftAccessoryHorizontalMargin + self.rightAccessoryHorizontalMargin; + + if (self.leftAccessoryView && self.rightAccessoryView) + preferredWidth += BETWEEN_ACCESSORIES_MARGIN; + } + + // ensure we're big enough to fit our graphics! + preferredWidth = fmaxf(preferredWidth, CALLOUT_MIN_WIDTH); + + // ask to be smaller if we have space, otherwise we'll fit into what we have by truncating the title/subtitle. + return CGSizeMake(fminf(preferredWidth, size.width), self.calloutHeight); +} + +- (CGSize)offsetToContainRect:(CGRect)innerRect inRect:(CGRect)outerRect { + CGFloat nudgeRight = fmaxf(0, CGRectGetMinX(outerRect) - CGRectGetMinX(innerRect)); + CGFloat nudgeLeft = fminf(0, CGRectGetMaxX(outerRect) - CGRectGetMaxX(innerRect)); + CGFloat nudgeTop = fmaxf(0, CGRectGetMinY(outerRect) - CGRectGetMinY(innerRect)); + CGFloat nudgeBottom = fminf(0, CGRectGetMaxY(outerRect) - CGRectGetMaxY(innerRect)); + return CGSizeMake(nudgeLeft ? nudgeLeft : nudgeRight, nudgeTop ? nudgeTop : nudgeBottom); +} + +- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated { + [self presentCalloutFromRect:rect inLayer:view.layer ofView:view constrainedToLayer:constrainedView.layer animated:animated]; +} + +- (void)presentCalloutFromRect:(CGRect)rect inLayer:(CALayer *)layer constrainedToLayer:(CALayer *)constrainedLayer animated:(BOOL)animated { + [self presentCalloutFromRect:rect inLayer:layer ofView:nil constrainedToLayer:constrainedLayer animated:animated]; +} + +// this private method handles both CALayer and UIView parents depending on what's passed. +- (void)presentCalloutFromRect:(CGRect)rect inLayer:(CALayer *)layer ofView:(UIView *)view constrainedToLayer:(CALayer *)constrainedLayer animated:(BOOL)animated { + + // Sanity check: dismiss this callout immediately if it's displayed somewhere + if (self.layer.superlayer) [self dismissCalloutAnimated:NO]; + + // cancel all animations that may be in progress + [self.layer removeAnimationForKey:@"present"]; + [self.layer removeAnimationForKey:@"dismiss"]; + + // figure out the constrained view's rect in our popup view's coordinate system + CGRect constrainedRect = [constrainedLayer convertRect:constrainedLayer.bounds toLayer:layer]; + + // apply our edge constraints + constrainedRect = UIEdgeInsetsInsetRect(constrainedRect, self.constrainedInsets); + + constrainedRect = CGRectInset(constrainedRect, COMFORTABLE_MARGIN, COMFORTABLE_MARGIN); + + // form our subviews based on our content set so far + [self rebuildSubviews]; + + // apply title/subtitle (if present + self.titleLabel.text = self.title; + self.subtitleLabel.text = self.subtitle; + + // size the callout to fit the width constraint as best as possible + self.frameSize = [self sizeThatFits:CGSizeMake(constrainedRect.size.width, self.calloutHeight)]; + + // how much room do we have in the constraint box, both above and below our target rect? + CGFloat topSpace = CGRectGetMinY(rect) - CGRectGetMinY(constrainedRect); + CGFloat bottomSpace = CGRectGetMaxY(constrainedRect) - CGRectGetMaxY(rect); + + // we prefer to point our arrow down. + SMCalloutArrowDirection bestDirection = SMCalloutArrowDirectionDown; + + // we'll point it up though if that's the only option you gave us. + if (self.permittedArrowDirection == SMCalloutArrowDirectionUp) + bestDirection = SMCalloutArrowDirectionUp; + + // or, if we don't have enough space on the top and have more space on the bottom, and you + // gave us a choice, then pointing up is the better option. + if (self.permittedArrowDirection == SMCalloutArrowDirectionAny && topSpace < self.calloutHeight && bottomSpace > topSpace) + bestDirection = SMCalloutArrowDirectionUp; + + self.currentArrowDirection = bestDirection; + + // we want to point directly at the horizontal center of the given rect. calculate our "anchor point" in terms of our + // target view's coordinate system. make sure to offset the anchor point as requested if necessary. + CGFloat anchorX = self.calloutOffset.x + CGRectGetMidX(rect); + CGFloat anchorY = self.calloutOffset.y + (bestDirection == SMCalloutArrowDirectionDown ? CGRectGetMinY(rect) : CGRectGetMaxY(rect)); + + // we prefer to sit centered directly above our anchor + CGFloat calloutX = roundf(anchorX - self.frameWidth / 2); + + // but not if it's going to get too close to the edge of our constraints + if (calloutX < constrainedRect.origin.x) + calloutX = constrainedRect.origin.x; + + if (calloutX > constrainedRect.origin.x+constrainedRect.size.width-self.frameWidth) + calloutX = constrainedRect.origin.x+constrainedRect.size.width-self.frameWidth; + + // what's the farthest to the left and right that we could point to, given our background image constraints? + CGFloat minPointX = calloutX + self.backgroundView.anchorMargin; + CGFloat maxPointX = calloutX + self.frameWidth - self.backgroundView.anchorMargin; + + // we may need to scoot over to the left or right to point at the correct spot + CGFloat adjustX = 0; + if (anchorX < minPointX) adjustX = anchorX - minPointX; + if (anchorX > maxPointX) adjustX = anchorX - maxPointX; + + // add the callout to the given layer (or view if possible, to receive touch events) + if (view) + [view addSubview:self]; + else + [layer addSublayer:self.layer]; + + CGPoint calloutOrigin = { + .x = calloutX + adjustX, + .y = bestDirection == SMCalloutArrowDirectionDown ? (anchorY - self.calloutHeight) : anchorY + }; + + self.frameOrigin = calloutOrigin; + + // now set the *actual* anchor point for our layer so that our "popup" animation starts from this point. + CGPoint anchorPoint = [layer convertPoint:CGPointMake(anchorX, anchorY) toLayer:self.layer]; + + // pass on the anchor point to our background view so it knows where to draw the arrow + self.backgroundView.arrowPoint = anchorPoint; + + // adjust it to unit coordinates for the actual layer.anchorPoint property + anchorPoint.x /= self.frameWidth; + anchorPoint.y /= self.frameHeight; + self.layer.anchorPoint = anchorPoint; + + // setting the anchor point moves the view a bit, so we need to reset + self.frameOrigin = calloutOrigin; + + // make sure our frame is not on half-pixels or else we may be blurry! + CGFloat scale = [UIScreen mainScreen].scale; + self.frameX = floorf(self.frameX*scale)/scale; + self.frameY = floorf(self.frameY*scale)/scale; + + // layout now so we can immediately start animating to the final position if needed + [self setNeedsLayout]; + [self layoutIfNeeded]; + + // if we're outside the bounds of our constraint rect, we'll give our delegate an opportunity to shift us into position. + // consider both our size and the size of our target rect (which we'll assume to be the size of the content you want to scroll into view. + CGRect contentRect = CGRectUnion(self.frame, rect); + CGSize offset = [self offsetToContainRect:contentRect inRect:constrainedRect]; + + NSTimeInterval delay = 0; + self.popupCancelled = NO; // reset this before calling our delegate below + + if ([self.delegate respondsToSelector:@selector(calloutView:delayForRepositionWithSize:)] && !CGSizeEqualToSize(offset, CGSizeZero)) + delay = [self.delegate calloutView:(id)self delayForRepositionWithSize:offset]; + + // there's a chance that user code in the delegate method may have called -dismissCalloutAnimated to cancel things; if that + // happened then we need to bail! + if (self.popupCancelled) return; + + // now we want to mask our contents to our background view (if requested) to match the iOS 7 style + self.containerView.layer.mask = self.backgroundView.contentMask; + + // if we need to delay, we don't want to be visible while we're delaying, so hide us in preparation for our popup + self.hidden = YES; + + // create the appropriate animation, even if we're not animated + CAAnimation *animation = [self animationWithType:self.presentAnimation presenting:YES]; + + // nuke the duration if no animation requested - we'll still need to "run" the animation to get delays and callbacks + if (!animated) + animation.duration = 0.0000001; // can't be zero or the animation won't "run" + + animation.beginTime = CACurrentMediaTime() + delay; + animation.delegate = self; + + [self.layer addAnimation:animation forKey:@"present"]; +} + +- (void)animationDidStart:(CAAnimation *)anim { + BOOL presenting = [[anim valueForKey:@"presenting"] boolValue]; + + if (presenting) { + if ([_delegate respondsToSelector:@selector(calloutViewWillAppear:)]) + [_delegate calloutViewWillAppear:(id)self]; + + // ok, animation is on, let's make ourselves visible! + self.hidden = NO; + } + else if (!presenting) { + if ([_delegate respondsToSelector:@selector(calloutViewWillDisappear:)]) + [_delegate calloutViewWillDisappear:(id)self]; + } +} + +- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)finished { + BOOL presenting = [[anim valueForKey:@"presenting"] boolValue]; + + if (presenting && finished) { + if ([_delegate respondsToSelector:@selector(calloutViewDidAppear:)]) + [_delegate calloutViewDidAppear:(id)self]; + } + else if (!presenting && finished) { + + [self removeFromParent]; + [self.layer removeAnimationForKey:@"dismiss"]; + + if ([_delegate respondsToSelector:@selector(calloutViewDidDisappear:)]) + [_delegate calloutViewDidDisappear:(id)self]; + } +} + +- (void)dismissCalloutAnimated:(BOOL)animated { + + // cancel all animations that may be in progress + [self.layer removeAnimationForKey:@"present"]; + [self.layer removeAnimationForKey:@"dismiss"]; + + self.popupCancelled = YES; + + if (animated) { + CAAnimation *animation = [self animationWithType:self.dismissAnimation presenting:NO]; + animation.delegate = self; + [self.layer addAnimation:animation forKey:@"dismiss"]; + } + else { + [self removeFromParent]; + } +} + +- (void)removeFromParent { + if (self.superview) + [self removeFromSuperview]; + else { + // removing a layer from a superlayer causes an implicit fade-out animation that we wish to disable. + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + [self.layer removeFromSuperlayer]; + [CATransaction commit]; + } +} + +- (CAAnimation *)animationWithType:(SMCalloutAnimation)type presenting:(BOOL)presenting { + CAAnimation *animation = nil; + + if (type == SMCalloutAnimationBounce) { + + CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"]; + fade.duration = 0.23; + fade.fromValue = presenting ? @0.0 : @1.0; + fade.toValue = presenting ? @1.0 : @0.0; + fade.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + + CABasicAnimation *bounce = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + bounce.duration = 0.23; + bounce.fromValue = presenting ? @0.7 : @1.0; + bounce.toValue = presenting ? @1.0 : @0.7; + bounce.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.59367:0.12066:0.18878:1.5814]; + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.animations = @[fade, bounce]; + group.duration = 0.23; + + animation = group; + } + else if (type == SMCalloutAnimationFade) { + CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"]; + fade.duration = 1.0/3.0; + fade.fromValue = presenting ? @0.0 : @1.0; + fade.toValue = presenting ? @1.0 : @0.0; + animation = fade; + } + else if (type == SMCalloutAnimationStretch) { + CABasicAnimation *stretch = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + stretch.duration = 0.1; + stretch.fromValue = presenting ? @0.0 : @1.0; + stretch.toValue = presenting ? @1.0 : @0.0; + animation = stretch; + } + + // CAAnimation is KVC compliant, so we can store whether we're presenting for lookup in our delegate methods + [animation setValue:@(presenting) forKey:@"presenting"]; + + animation.fillMode = kCAFillModeForwards; + animation.removedOnCompletion = NO; + return animation; +} + +- (void)layoutSubviews { + + self.containerView.frame = self.bounds; + self.backgroundView.frame = self.bounds; + + // if we're pointing up, we'll need to push almost everything down a bit + CGFloat dy = self.currentArrowDirection == SMCalloutArrowDirectionUp ? TOP_ANCHOR_MARGIN : 0; + + self.titleViewOrDefault.frameX = self.innerContentMarginLeft; + self.titleViewOrDefault.frameY = (self.subtitleView || self.subtitle.length ? TITLE_SUB_TOP : TITLE_TOP) + dy; + self.titleViewOrDefault.frameWidth = self.frameWidth - self.innerContentMarginLeft - self.innerContentMarginRight; + + self.subtitleViewOrDefault.frameX = self.titleViewOrDefault.frameX; + self.subtitleViewOrDefault.frameY = SUBTITLE_TOP + dy; + self.subtitleViewOrDefault.frameWidth = self.titleViewOrDefault.frameWidth; + + self.leftAccessoryView.frameX = self.leftAccessoryHorizontalMargin; + self.leftAccessoryView.frameY = self.leftAccessoryVerticalMargin + dy; + + self.rightAccessoryView.frameX = self.frameWidth - self.rightAccessoryHorizontalMargin - self.rightAccessoryView.frameWidth; + self.rightAccessoryView.frameY = self.rightAccessoryVerticalMargin + dy; + + if (self.contentView) { + self.contentView.frameX = self.innerContentMarginLeft; + self.contentView.frameY = self.contentViewInset.top + dy; + } +} + +#pragma mark - Accessibility + +- (NSInteger)accessibilityElementCount { + return (!!self.leftAccessoryView + !!self.titleViewOrDefault + + !!self.subtitleViewOrDefault + !!self.rightAccessoryView); +} + +- (id)accessibilityElementAtIndex:(NSInteger)index { + if (index == 0) { + return self.leftAccessoryView ? self.leftAccessoryView : self.titleViewOrDefault; + } + if (index == 1) { + return self.leftAccessoryView ? self.titleViewOrDefault : self.subtitleViewOrDefault; + } + if (index == 2) { + return self.leftAccessoryView ? self.subtitleViewOrDefault : self.rightAccessoryView; + } + if (index == 3) { + return self.leftAccessoryView ? self.rightAccessoryView : nil; + } + return nil; +} + +- (NSInteger)indexOfAccessibilityElement:(id)element { + if (element == nil) return NSNotFound; + if (element == self.leftAccessoryView) return 0; + if (element == self.titleViewOrDefault) { + return self.leftAccessoryView ? 1 : 0; + } + if (element == self.subtitleViewOrDefault) { + return self.leftAccessoryView ? 2 : 1; + } + if (element == self.rightAccessoryView) { + return self.leftAccessoryView ? 3 : 2; + } + return NSNotFound; +} + +@end + +// import this known "private API" from SMCalloutBackgroundView +@interface SMCalloutBackgroundView (EmbeddedImages) ++ (UIImage *)embeddedImageNamed:(NSString *)name; +@end + +// +// Callout Background View. +// + +@interface SMCalloutMaskedBackgroundView () +@property (nonatomic, strong) UIView *containerView, *containerBorderView, *arrowView; +@property (nonatomic, strong) UIImageView *arrowImageView, *arrowHighlightedImageView, *arrowBorderView; +@end + +static UIImage *blackArrowImage = nil, *whiteArrowImage = nil, *grayArrowImage = nil; + +@implementation SMCalloutMaskedBackgroundView + +- (id)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + + // Here we're mimicking the very particular (and odd) structure of the system callout view. + // The hierarchy and view/layer values were discovered by inspecting map kit using Reveal.app + + self.containerView = [UIView new]; + self.containerView.backgroundColor = [UIColor whiteColor]; + self.containerView.alpha = 0.96; + self.containerView.layer.cornerRadius = 8; + self.containerView.layer.shadowRadius = 30; + self.containerView.layer.shadowOpacity = 0.1; + + self.containerBorderView = [UIView new]; + self.containerBorderView.layer.borderColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor; + self.containerBorderView.layer.borderWidth = 0.5; + self.containerBorderView.layer.cornerRadius = 8.5; + + if (!blackArrowImage) { + blackArrowImage = [SMCalloutBackgroundView embeddedImageNamed:@"CalloutArrow"]; + whiteArrowImage = [self image:blackArrowImage withColor:[UIColor whiteColor]]; + grayArrowImage = [self image:blackArrowImage withColor:[UIColor colorWithWhite:0.85 alpha:1]]; + } + + self.anchorHeight = 13; + self.anchorMargin = 27; + + self.arrowView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, blackArrowImage.size.width, blackArrowImage.size.height)]; + self.arrowView.alpha = 0.96; + self.arrowImageView = [[UIImageView alloc] initWithImage:whiteArrowImage]; + self.arrowHighlightedImageView = [[UIImageView alloc] initWithImage:grayArrowImage]; + self.arrowHighlightedImageView.hidden = YES; + self.arrowBorderView = [[UIImageView alloc] initWithImage:blackArrowImage]; + self.arrowBorderView.alpha = 0.1; + self.arrowBorderView.frameY = 0.5; + + [self addSubview:self.containerView]; + [self.containerView addSubview:self.containerBorderView]; + [self addSubview:self.arrowView]; + [self.arrowView addSubview:self.arrowBorderView]; + [self.arrowView addSubview:self.arrowImageView]; + [self.arrowView addSubview:self.arrowHighlightedImageView]; + } + return self; +} + +// Make sure we relayout our images when our arrow point changes! +- (void)setArrowPoint:(CGPoint)arrowPoint { + [super setArrowPoint:arrowPoint]; + [self setNeedsLayout]; +} + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.containerView.backgroundColor = highlighted ? [UIColor colorWithWhite:0.85 alpha:1] : [UIColor whiteColor]; + self.arrowImageView.hidden = highlighted; + self.arrowHighlightedImageView.hidden = !highlighted; +} + +- (UIImage *)image:(UIImage *)image withColor:(UIColor *)color { + + UIGraphicsBeginImageContextWithOptions(image.size, NO, 0); + CGRect imageRect = (CGRect){.size=image.size}; + CGContextRef c = UIGraphicsGetCurrentContext(); + CGContextTranslateCTM(c, 0, image.size.height); + CGContextScaleCTM(c, 1, -1); + CGContextClipToMask(c, imageRect, image.CGImage); + [color setFill]; + CGContextFillRect(c, imageRect); + UIImage *whiteImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return whiteImage; +} + +- (void)layoutSubviews { + + BOOL pointingUp = self.arrowPoint.y < self.frameHeight/2; + + // if we're pointing up, we'll need to push almost everything down a bit + CGFloat dy = pointingUp ? TOP_ANCHOR_MARGIN : 0; + + self.containerView.frame = CGRectMake(0, dy, self.frameWidth, self.frameHeight - self.arrowView.frameHeight + 0.5); + self.containerBorderView.frame = CGRectInset(self.containerView.bounds, -0.5, -0.5); + + self.arrowView.frameX = roundf(self.arrowPoint.x - self.arrowView.frameWidth / 2); + + if (pointingUp) { + self.arrowView.frameY = 1; + self.arrowView.transform = CGAffineTransformMakeRotation(M_PI); + } + else { + self.arrowView.frameY = self.containerView.frameHeight - 0.5; + self.arrowView.transform = CGAffineTransformIdentity; + } +} + +- (CALayer *)contentMask { + + UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0); + + [self.layer renderInContext:UIGraphicsGetCurrentContext()]; + + UIImage *maskImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + CALayer *layer = [CALayer layer]; + layer.frame = self.bounds; + layer.contents = (id)maskImage.CGImage; + return layer; +} + +@end + +@implementation SMCalloutBackgroundView + ++ (NSData *)dataWithBase64EncodedString:(NSString *)string { + // + // NSData+Base64.m + // + // Version 1.0.2 + // + // Created by Nick Lockwood on 12/01/2012. + // Copyright (C) 2012 Charcoal Design + // + // Distributed under the permissive zlib License + // Get the latest version from here: + // + // https://github.com/nicklockwood/Base64 + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // + // 3. This notice may not be removed or altered from any source distribution. + // + const char lookup[] = { + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 99, 99, 99, + 99, 0, 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, 99, 99, 99, 99, 99, + 99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99 + }; + + NSData *inputData = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + long long inputLength = [inputData length]; + const unsigned char *inputBytes = [inputData bytes]; + + long long maxOutputLength = (inputLength / 4 + 1) * 3; + NSMutableData *outputData = [NSMutableData dataWithLength:(NSUInteger)maxOutputLength]; + unsigned char *outputBytes = (unsigned char *)[outputData mutableBytes]; + + int accumulator = 0; + long long outputLength = 0; + unsigned char accumulated[] = {0, 0, 0, 0}; + for (long long i = 0; i < inputLength; i++) { + unsigned char decoded = lookup[inputBytes[i] & 0x7F]; + if (decoded != 99) { + accumulated[accumulator] = decoded; + if (accumulator == 3) { + outputBytes[outputLength++] = (accumulated[0] << 2) | (accumulated[1] >> 4); + outputBytes[outputLength++] = (accumulated[1] << 4) | (accumulated[2] >> 2); + outputBytes[outputLength++] = (accumulated[2] << 6) | accumulated[3]; + } + accumulator = (accumulator + 1) % 4; + } + } + + //handle left-over data + if (accumulator > 0) outputBytes[outputLength] = (accumulated[0] << 2) | (accumulated[1] >> 4); + if (accumulator > 1) outputBytes[++outputLength] = (accumulated[1] << 4) | (accumulated[2] >> 2); + if (accumulator > 2) outputLength++; + + //truncate data to match actual output length + outputData.length = (NSUInteger)outputLength; + return outputLength? outputData: nil; +} + ++ (UIImage *)embeddedImageNamed:(NSString *)name { + CGFloat screenScale = [UIScreen mainScreen].scale; + if (screenScale > 1.0) { + name = [name stringByAppendingString:@"_2x"]; + screenScale = 2.0; + } + + SEL selector = NSSelectorFromString(name); + + if (![(id)self respondsToSelector:selector]) { + NSLog(@"Could not find an embedded image. Ensure that you've added a class-level method named +%@", name); + return nil; + } + + // We need to hush the compiler here - but we know what we're doing! + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Warc-performSelector-leaks" + NSString *base64String = [(id)self performSelector:selector]; + #pragma clang diagnostic pop + + UIImage *rawImage = [UIImage imageWithData:[self dataWithBase64EncodedString:base64String]]; + return [UIImage imageWithCGImage:rawImage.CGImage scale:screenScale orientation:UIImageOrientationUp]; +} + ++ (NSString *)CalloutArrow { return @"iVBORw0KGgoAAAANSUhEUgAAACcAAAANCAYAAAAqlHdlAAAAHGlET1QAAAACAAAAAAAAAAcAAAAoAAAABwAAAAYAAADJEgYpIwAAAJVJREFUOBFiYIAAdn5+fkFOTkE5Dg5eW05O3lJOTr6zQPyfDhhoD28pxF5BOZA7gE5ih7oLN8XJyR8MdNwrGjkQaC5/MG7biZDh4OBXBDruLpUdeBdkLhHWE1bCzs6nAnTcUyo58DnIPMK2kqAC6DALIP5JoQNB+i1IsJZ4pcBEm0iJ40D6ibeNDJVAx00k04ETSbUOAAAA//+SwicfAAAAe0lEQVRjYCAdMHNy8u7l5OT7Tzzm3Qu0hpl0q8jQwcPDIwp02B0iHXeHl5dXhAxryNfCzc2tC3TcJwIO/ARSR74tFOjk4uL1BzruHw4H/gPJU2A85Vq5uPjTgY77g+bAPyBxyk2nggkcHPxOnJz8B4AOfAGiQXwqGMsAACGK1kPPMHNBAAAAAElFTkSuQmCC"; } + ++ (NSString *)CalloutArrow_2x { return @"iVBORw0KGgoAAAANSUhEUgAAAE4AAAAaCAYAAAAZtWr8AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAHGlET1QAAAACAAAAAAAAAA0AAAAoAAAADQAAAA0AAAFMRh0LGwAAARhJREFUWAnclbENwjAQRZ0mih2fDYgsQEVDxQZMgKjpWYAJkBANI8AGDIEoM0WkzBDRAf8klB44g0OkU1zE3/+9RIpS7VVY730/y/woTWlsjJ9iPcN9pbXfY85auyvm/qcDNmb0e2Z+sk/ZBTthN0oVttX12mJIWeaWEFf+kbySmZQa0msu3nzaGJprTXV3BVLNDG/if7bNOTeAvFP35NGJu39GL7Abb27bFXncVQBZLgJf3jp+ebSWIxZMgrxdvPJoJ4gqHpXgV36ITR46HUGaiNMKB6YQd4lI3gV8qTBjmDhrbQFxVQTyKu4ShjJQap7nE4hrfiiv4Q6B8MLGat1bQNztB/JwZm8Rli5wujFu821xfGZgLPUAAAD//4wvm4gAAAD7SURBVOWXMQ6CMBiFgaFpi6VyBEedXJy4hMQTeBSvRDgJEySegI3EQWOivkZnqUB/k0LyL7R9L++D9G+DwP0TCZGUqCdRlYgUuY9F4JCmqQa0hgBcY7wIItFZMLZYS5l0ruAZbXhs6BIROgmhcoB7OIAHTZUTRqG3wp9xmhqc0aRPQu8YAlwxIbwCEUL6GH9wfDcLXY2HpyvvmkHf9+BcrwCuHQGvNRp9Pl6OY0PPAO42AB7WqMxLKLahpFR7gLv/AA9zPe+gtvAMCIC7WMC7CqEPtrqzmBfHyy3A1V/g1Th27GYBY0BIxrk6Ap65254/VZp30GID9JwteQEZrVMWXqGn8gAAAABJRU5ErkJggg=="; } + +@end + +// +// Our UIView frame helpers implementation +// + +@implementation UIView (SMFrameAdditions) + +- (CGPoint)frameOrigin { return self.frame.origin; } +- (void)setFrameOrigin:(CGPoint)origin { self.frame = (CGRect){ .origin=origin, .size=self.frame.size }; } + +- (CGFloat)frameX { return self.frame.origin.x; } +- (void)setFrameX:(CGFloat)x { self.frame = (CGRect){ .origin.x=x, .origin.y=self.frame.origin.y, .size=self.frame.size }; } + +- (CGFloat)frameY { return self.frame.origin.y; } +- (void)setFrameY:(CGFloat)y { self.frame = (CGRect){ .origin.x=self.frame.origin.x, .origin.y=y, .size=self.frame.size }; } + +- (CGSize)frameSize { return self.frame.size; } +- (void)setFrameSize:(CGSize)size { self.frame = (CGRect){ .origin=self.frame.origin, .size=size }; } + +- (CGFloat)frameWidth { return self.frame.size.width; } +- (void)setFrameWidth:(CGFloat)width { self.frame = (CGRect){ .origin=self.frame.origin, .size.width=width, .size.height=self.frame.size.height }; } + +- (CGFloat)frameHeight { return self.frame.size.height; } +- (void)setFrameHeight:(CGFloat)height { self.frame = (CGRect){ .origin=self.frame.origin, .size.width=self.frame.size.width, .size.height=height }; } + +- (CGFloat)frameLeft { return self.frame.origin.x; } +- (void)setFrameLeft:(CGFloat)left { self.frame = (CGRect){ .origin.x=left, .origin.y=self.frame.origin.y, .size.width=fmaxf(self.frame.origin.x+self.frame.size.width-left,0), .size.height=self.frame.size.height }; } + +- (CGFloat)frameTop { return self.frame.origin.y; } +- (void)setFrameTop:(CGFloat)top { self.frame = (CGRect){ .origin.x=self.frame.origin.x, .origin.y=top, .size.width=self.frame.size.width, .size.height=fmaxf(self.frame.origin.y+self.frame.size.height-top,0) }; } + +- (CGFloat)frameRight { return self.frame.origin.x + self.frame.size.width; } +- (void)setFrameRight:(CGFloat)right { self.frame = (CGRect){ .origin=self.frame.origin, .size.width=fmaxf(right-self.frame.origin.x,0), .size.height=self.frame.size.height }; } + +- (CGFloat)frameBottom { return self.frame.origin.y + self.frame.size.height; } +- (void)setFrameBottom:(CGFloat)bottom { self.frame = (CGRect){ .origin=self.frame.origin, .size.width=self.frame.size.width, .size.height=fmaxf(bottom-self.frame.origin.y,0) }; } + +@end diff --git a/Pods/SMCalloutView/SMClassicCalloutView.h b/Pods/SMCalloutView/SMClassicCalloutView.h new file mode 100644 index 0000000..724c987 --- /dev/null +++ b/Pods/SMCalloutView/SMClassicCalloutView.h @@ -0,0 +1,39 @@ +#import +#import "SMCalloutView.h" + +/* + + SMClassicCalloutView + -------------------- + Created by Nick Farina (nfarina@gmail.com) + Version 1.1 + + */ + +@protocol SMCalloutViewDelegate; +@class SMCalloutBackgroundView; + +// +// Classic Callout view. +// + +@interface SMClassicCalloutView : SMCalloutView + +// One thing to note about the classic callout is that it will ignore the "constrainedInsets" property. That property is designed for iOS-7 +// style presentation where your target view surface may be operlapped by navigation bars, tab bars, etc. + +@end + +// +// Classes responsible for drawing the background graphic with the pointy arrow. +// + +// Draws a background composed of stretched prerendered images that you can customize. Uses the embedded iOS 6 graphics by default. +@interface SMCalloutImageBackgroundView : SMCalloutBackgroundView +@property (nonatomic, strong) UIImage *leftCapImage, *rightCapImage, *topAnchorImage, *bottomAnchorImage, *backgroundImage; +@end + +// Draws a custom background matching the system background but can grow in height. +@interface SMCalloutDrawnBackgroundView : SMCalloutBackgroundView +@end + diff --git a/Pods/SMCalloutView/SMClassicCalloutView.m b/Pods/SMCalloutView/SMClassicCalloutView.m new file mode 100644 index 0000000..4c98303 --- /dev/null +++ b/Pods/SMCalloutView/SMClassicCalloutView.m @@ -0,0 +1,871 @@ +#import "SMClassicCalloutView.h" +#import + +// +// UIView frame helpers - we do a lot of UIView frame fiddling in this class; these functions help keep things readable. +// + +@interface UIView (SMFrameAdditions) +@property (nonatomic, assign) CGPoint frameOrigin; +@property (nonatomic, assign) CGSize frameSize; +@property (nonatomic, assign) CGFloat frameX, frameY, frameWidth, frameHeight; // normal rect properties +@property (nonatomic, assign) CGFloat frameLeft, frameTop, frameRight, frameBottom; // these will stretch/shrink the rect +@end + +// +// Callout View. +// + +#define CALLOUT_DEFAULT_MIN_WIDTH 75 // our image-based background graphics limit us to this minimum width... +#define CALLOUT_DEFAULT_HEIGHT 70 // ...and allow only for this exact height. +#define CALLOUT_DEFAULT_WIDTH 153 // default "I give up" width when we are asked to present in a space less than our min width +#define TITLE_MARGIN 17 // the title view's normal horizontal margin from the edges of our callout view +#define TITLE_TOP 11 // the top of the title view when no subtitle is present +#define TITLE_SUB_TOP 3 // the top of the title view when a subtitle IS present +#define TITLE_HEIGHT 22 // title height, fixed +#define SUBTITLE_TOP 25 // the top of the subtitle, when present +#define SUBTITLE_HEIGHT 16 // subtitle height, fixed +#define TITLE_ACCESSORY_MARGIN 6 // the margin between the title and an accessory if one is present (on either side) +#define ACCESSORY_MARGIN 14 // the accessory's margin from the edges of our callout view +#define ACCESSORY_TOP 8 // the top of the accessory "area" in which accessory views are placed +#define ACCESSORY_HEIGHT 32 // the "suggested" maximum height of an accessory view. shorter accessories will be vertically centered +#define BETWEEN_ACCESSORIES_MARGIN 7 // if we have no title or subtitle, but have two accessory views, then this is the space between them +#define ANCHOR_MARGIN 39 // the smallest possible distance from the edge of our control to the "tip" of the anchor, from either left or right +#define TOP_ANCHOR_MARGIN 13 // all the above measurements assume a bottom anchor! if we're pointing "up" we'll need to add this top margin to everything. +#define BOTTOM_ANCHOR_MARGIN 10 // if using a bottom anchor, we'll need to account for the shadow below the "tip" +#define REPOSITION_MARGIN 10 // when we try to reposition content to be visible, we'll consider this margin around your target rect + +#define TOP_SHADOW_BUFFER 2 // height offset buffer to account for top shadow +#define BOTTOM_SHADOW_BUFFER 5 // height offset buffer to account for bottom shadow +#define OFFSET_FROM_ORIGIN 5 // distance to offset vertically from the rect origin of the callout +#define ANCHOR_HEIGHT 14 // height to use for the anchor +#define ANCHOR_MARGIN_MIN 24 // the smallest possible distance from the edge of our control to the edge of the anchor, from either left or right + +@interface SMCalloutView (PrivateMethods) +@property (nonatomic, strong) UILabel *titleLabel, *subtitleLabel; +@property (nonatomic, assign) SMCalloutArrowDirection currentArrowDirection; +@property (nonatomic, assign) BOOL popupCancelled; +//@property (nonatomic, strong) UIImageView *leftCap, *rightCap, *topAnchor, *bottomAnchor, *leftBackground, *rightBackground; +@end + +@interface SMClassicCalloutView () + +@end + +@implementation SMClassicCalloutView + +- (UIView *)titleViewOrDefault { + if (self.titleView) + // if you have a custom title view defined, return that. + return self.titleView; + else { + if (!self.titleLabel) { + // create a default titleView + self.titleLabel = [UILabel new]; + self.titleLabel.frameHeight = TITLE_HEIGHT; + self.titleLabel.opaque = NO; + self.titleLabel.backgroundColor = [UIColor clearColor]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:17]; + self.titleLabel.textColor = [UIColor whiteColor]; + self.titleLabel.shadowColor = [UIColor colorWithWhite:0 alpha:0.5]; + self.titleLabel.shadowOffset = CGSizeMake(0, -1); + } + return self.titleLabel; + } +} + +- (UIView *)subtitleViewOrDefault { + if (self.subtitleView) + // if you have a custom subtitle view defined, return that. + return self.subtitleView; + else { + if (!self.subtitleLabel) { + // create a default subtitleView + self.subtitleLabel = [UILabel new]; + self.subtitleLabel.frameHeight = SUBTITLE_HEIGHT; + self.subtitleLabel.opaque = NO; + self.subtitleLabel.backgroundColor = [UIColor clearColor]; + self.subtitleLabel.font = [UIFont systemFontOfSize:12]; + self.subtitleLabel.textColor = [UIColor whiteColor]; + self.subtitleLabel.shadowColor = [UIColor colorWithWhite:0 alpha:0.5]; + self.subtitleLabel.shadowOffset = CGSizeMake(0, -1); + } + return self.subtitleLabel; + } +} + +- (SMCalloutBackgroundView *)defaultBackgroundView { + return [SMCalloutDrawnBackgroundView new]; +} + +- (void)rebuildSubviews { + // remove and re-add our appropriate subviews in the appropriate order + [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + [self setNeedsDisplay]; + + [self addSubview:self.backgroundView]; + + if (self.contentView) { + [self addSubview:self.contentView]; + } + else { + if (self.titleViewOrDefault) [self addSubview:self.titleViewOrDefault]; + if (self.subtitleViewOrDefault) [self addSubview:self.subtitleViewOrDefault]; + } + if (self.leftAccessoryView) [self addSubview:self.leftAccessoryView]; + if (self.rightAccessoryView) [self addSubview:self.rightAccessoryView]; +} + +- (CGFloat)innerContentMarginLeft { + if (self.leftAccessoryView) + return ACCESSORY_MARGIN + self.leftAccessoryView.frameWidth + TITLE_ACCESSORY_MARGIN; + else + return TITLE_MARGIN; +} + +- (CGFloat)innerContentMarginRight { + if (self.rightAccessoryView) + return ACCESSORY_MARGIN + self.rightAccessoryView.frameWidth + TITLE_ACCESSORY_MARGIN; + else + return TITLE_MARGIN; +} + +- (CGFloat)calloutHeight { + if (self.contentView) + return self.contentView.frameHeight + TITLE_TOP*2 + ANCHOR_HEIGHT + BOTTOM_ANCHOR_MARGIN; + else + return CALLOUT_DEFAULT_HEIGHT; +} + +- (CGSize)sizeThatFits:(CGSize)size { + + // odd behavior, but mimicking the system callout view + if (size.width < CALLOUT_DEFAULT_MIN_WIDTH) + return CGSizeMake(CALLOUT_DEFAULT_WIDTH, self.calloutHeight); + + // calculate how much non-negotiable space we need to reserve for margin and accessories + CGFloat margin = self.innerContentMarginLeft + self.innerContentMarginRight; + + // how much room is left for text? + CGFloat availableWidthForText = size.width - margin; + + // no room for text? then we'll have to squeeze into the given size somehow. + if (availableWidthForText < 0) + availableWidthForText = 0; + + CGSize preferredTitleSize = [self.titleViewOrDefault sizeThatFits:CGSizeMake(availableWidthForText, TITLE_HEIGHT)]; + CGSize preferredSubtitleSize = [self.subtitleViewOrDefault sizeThatFits:CGSizeMake(availableWidthForText, SUBTITLE_HEIGHT)]; + + // total width we'd like + CGFloat preferredWidth; + + if (self.contentView) { + + // if we have a content view, then take our preferred size directly from that + preferredWidth = self.contentView.frameWidth + margin; + } + else if (preferredTitleSize.width >= 0.000001 || preferredSubtitleSize.width >= 0.000001) { + + // if we have a title or subtitle, then our assumed margins are valid, and we can apply them + preferredWidth = fmaxf(preferredTitleSize.width, preferredSubtitleSize.width) + margin; + } + else { + // ok we have no title or subtitle to speak of. In this case, the system callout would actually not display + // at all! But we can handle it. + preferredWidth = self.leftAccessoryView.frameWidth + self.rightAccessoryView.frameWidth + ACCESSORY_MARGIN*2; + + if (self.leftAccessoryView && self.rightAccessoryView) + preferredWidth += BETWEEN_ACCESSORIES_MARGIN; + } + + // ensure we're big enough to fit our graphics! + preferredWidth = fmaxf(preferredWidth, CALLOUT_DEFAULT_MIN_WIDTH); + + // ask to be smaller if we have space, otherwise we'll fit into what we have by truncating the title/subtitle. + return CGSizeMake(fminf(preferredWidth, size.width), self.calloutHeight); +} + +- (CGSize)offsetToContainRect:(CGRect)innerRect inRect:(CGRect)outerRect { + CGFloat nudgeRight = fmaxf(0, CGRectGetMinX(outerRect) - CGRectGetMinX(innerRect)); + CGFloat nudgeLeft = fminf(0, CGRectGetMaxX(outerRect) - CGRectGetMaxX(innerRect)); + CGFloat nudgeTop = fmaxf(0, CGRectGetMinY(outerRect) - CGRectGetMinY(innerRect)); + CGFloat nudgeBottom = fminf(0, CGRectGetMaxY(outerRect) - CGRectGetMaxY(innerRect)); + return CGSizeMake(nudgeLeft ? nudgeLeft : nudgeRight, nudgeTop ? nudgeTop : nudgeBottom); +} + +- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated { + [self presentCalloutFromRect:rect inLayer:view.layer ofView:view constrainedToLayer:constrainedView.layer animated:animated]; +} + +- (void)presentCalloutFromRect:(CGRect)rect inLayer:(CALayer *)layer constrainedToLayer:(CALayer *)constrainedLayer animated:(BOOL)animated { + [self presentCalloutFromRect:rect inLayer:layer ofView:nil constrainedToLayer:constrainedLayer animated:animated]; +} + +// this private method handles both CALayer and UIView parents depending on what's passed. +- (void)presentCalloutFromRect:(CGRect)rect inLayer:(CALayer *)layer ofView:(UIView *)view constrainedToLayer:(CALayer *)constrainedLayer animated:(BOOL)animated { + + // Sanity check: dismiss this callout immediately if it's displayed somewhere + if (self.layer.superlayer) [self dismissCalloutAnimated:NO]; + + // figure out the constrained view's rect in our popup view's coordinate system + CGRect constrainedRect = [constrainedLayer convertRect:constrainedLayer.bounds toLayer:layer]; + + // apply our edge constraints + constrainedRect = UIEdgeInsetsInsetRect(constrainedRect, self.constrainedInsets); + + // form our subviews based on our content set so far + [self rebuildSubviews]; + + // apply title/subtitle (if present + self.titleLabel.text = self.title; + self.subtitleLabel.text = self.subtitle; + + // size the callout to fit the width constraint as best as possible + self.frameSize = [self sizeThatFits:CGSizeMake(constrainedRect.size.width, self.calloutHeight)]; + + // how much room do we have in the constraint box, both above and below our target rect? + CGFloat topSpace = CGRectGetMinY(rect) - CGRectGetMinY(constrainedRect); + CGFloat bottomSpace = CGRectGetMaxY(constrainedRect) - CGRectGetMaxY(rect); + + // we prefer to point our arrow down. + SMCalloutArrowDirection bestDirection = SMCalloutArrowDirectionDown; + + // we'll point it up though if that's the only option you gave us. + if (self.permittedArrowDirection == SMCalloutArrowDirectionUp) + bestDirection = SMCalloutArrowDirectionUp; + + // or, if we don't have enough space on the top and have more space on the bottom, and you + // gave us a choice, then pointing up is the better option. + if (self.permittedArrowDirection == SMCalloutArrowDirectionAny && topSpace < self.calloutHeight && bottomSpace > topSpace) + bestDirection = SMCalloutArrowDirectionUp; + + // we want to point directly at the horizontal center of the given rect. calculate our "anchor point" in terms of our + // target view's coordinate system. make sure to offset the anchor point as requested if necessary. + CGFloat anchorX = self.calloutOffset.x + CGRectGetMidX(rect); + CGFloat anchorY = self.calloutOffset.y + (bestDirection == SMCalloutArrowDirectionDown ? CGRectGetMinY(rect) : CGRectGetMaxY(rect)); + + // we prefer to sit in the exact center of our constrained view, so we have visually pleasing equal left/right margins. + CGFloat calloutX = roundf(CGRectGetMidX(constrainedRect) - self.frameWidth / 2); + + // what's the farthest to the left and right that we could point to, given our background image constraints? + CGFloat minPointX = calloutX + ANCHOR_MARGIN; + CGFloat maxPointX = calloutX + self.frameWidth - ANCHOR_MARGIN; + + // we may need to scoot over to the left or right to point at the correct spot + CGFloat adjustX = 0; + if (anchorX < minPointX) adjustX = anchorX - minPointX; + if (anchorX > maxPointX) adjustX = anchorX - maxPointX; + + // add the callout to the given layer (or view if possible, to receive touch events) + if (view) + [view addSubview:self]; + else + [layer addSublayer:self.layer]; + + CGPoint calloutOrigin = { + .x = calloutX + adjustX, + .y = bestDirection == SMCalloutArrowDirectionDown ? (anchorY - self.calloutHeight + BOTTOM_ANCHOR_MARGIN) : anchorY + }; + + self.currentArrowDirection = bestDirection; + + self.frameOrigin = calloutOrigin; + + // now set the *actual* anchor point for our layer so that our "popup" animation starts from this point. + CGPoint anchorPoint = [layer convertPoint:CGPointMake(anchorX, anchorY) toLayer:self.layer]; + + // pass on the anchor point to our background view so it knows where to draw the arrow + self.backgroundView.arrowPoint = anchorPoint; + + // adjust it to unit coordinates for the actual layer.anchorPoint property + anchorPoint.x /= self.frameWidth; + anchorPoint.y /= self.frameHeight; + self.layer.anchorPoint = anchorPoint; + + // setting the anchor point moves the view a bit, so we need to reset + self.frameOrigin = calloutOrigin; + + // make sure our frame is not on half-pixels or else we may be blurry! + self.frame = CGRectIntegral(self.frame); + + // layout now so we can immediately start animating to the final position if needed + [self setNeedsLayout]; + [self layoutIfNeeded]; + + // if we're outside the bounds of our constraint rect, we'll give our delegate an opportunity to shift us into position. + // consider both our size and the size of our target rect (which we'll assume to be the size of the content you want to scroll into view. + CGRect contentRect = CGRectUnion(self.frame, CGRectInset(rect, -REPOSITION_MARGIN, -REPOSITION_MARGIN)); + CGSize offset = [self offsetToContainRect:contentRect inRect:constrainedRect]; + + NSTimeInterval delay = 0; + self.popupCancelled = NO; // reset this before calling our delegate below + + if ([self.delegate respondsToSelector:@selector(calloutView:delayForRepositionWithSize:)] && !CGSizeEqualToSize(offset, CGSizeZero)) + delay = [self.delegate calloutView:(id)self delayForRepositionWithSize:offset]; + + // there's a chance that user code in the delegate method may have called -dismissCalloutAnimated to cancel things; if that + // happened then we need to bail! + if (self.popupCancelled) return; + + // if we need to delay, we don't want to be visible while we're delaying, so hide us in preparation for our popup + self.hidden = YES; + + // create the appropriate animation, even if we're not animated + CAAnimation *animation = [self animationWithType:self.presentAnimation presenting:YES]; + + // nuke the duration if no animation requested - we'll still need to "run" the animation to get delays and callbacks + if (!animated) + animation.duration = 0.0000001; // can't be zero or the animation won't "run" + + animation.beginTime = CACurrentMediaTime() + delay; + animation.delegate = self; + + [self.layer addAnimation:animation forKey:@"present"]; +} + +- (void)animationDidStart:(CAAnimation *)anim { + BOOL presenting = [[anim valueForKey:@"presenting"] boolValue]; + + if (presenting) { + if ([self.delegate respondsToSelector:@selector(calloutViewWillAppear:)]) + [self.delegate calloutViewWillAppear:(id)self]; + + // ok, animation is on, let's make ourselves visible! + self.hidden = NO; + } + else if (!presenting) { + if ([self.delegate respondsToSelector:@selector(calloutViewWillDisappear:)]) + [self.delegate calloutViewWillDisappear:(id)self]; + } +} + +- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)finished { + BOOL presenting = [[anim valueForKey:@"presenting"] boolValue]; + + if (presenting) { + if ([self.delegate respondsToSelector:@selector(calloutViewDidAppear:)]) + [self.delegate calloutViewDidAppear:(id)self]; + } + else if (!presenting) { + + [self removeFromParent]; + [self.layer removeAnimationForKey:@"dismiss"]; + + if ([self.delegate respondsToSelector:@selector(calloutViewDidDisappear:)]) + [self.delegate calloutViewDidDisappear:(id)self]; + } +} + +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + // we want to match the system callout view, which doesn't "capture" touches outside the accessory areas. This way you can click on other pins and things *behind* a translucent callout. + return + [self.leftAccessoryView pointInside:[self.leftAccessoryView convertPoint:point fromView:self] withEvent:nil] || + [self.rightAccessoryView pointInside:[self.rightAccessoryView convertPoint:point fromView:self] withEvent:nil] || + [self.contentView pointInside:[self.contentView convertPoint:point fromView:self] withEvent:nil] || + (!self.contentView && [self.titleView pointInside:[self.titleView convertPoint:point fromView:self] withEvent:nil]) || + (!self.contentView && [self.subtitleView pointInside:[self.subtitleView convertPoint:point fromView:self] withEvent:nil]); +} + +- (void)dismissCalloutAnimated:(BOOL)animated { + [self.layer removeAnimationForKey:@"present"]; + + self.popupCancelled = YES; + + if (animated) { + CAAnimation *animation = [self animationWithType:self.dismissAnimation presenting:NO]; + animation.delegate = self; + [self.layer addAnimation:animation forKey:@"dismiss"]; + } + else [self removeFromParent]; +} + +- (void)removeFromParent { + if (self.superview) + [self removeFromSuperview]; + else { + // removing a layer from a superlayer causes an implicit fade-out animation that we wish to disable. + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + [self.layer removeFromSuperlayer]; + [CATransaction commit]; + } +} + +- (CAAnimation *)animationWithType:(SMCalloutAnimation)type presenting:(BOOL)presenting { + CAAnimation *animation = nil; + + if (type == SMCalloutAnimationBounce) { + CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; + CAMediaTimingFunction *easeInOut = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + + bounceAnimation.values = @[@0.05, @1.11245, @0.951807, @1.0]; + bounceAnimation.keyTimes = @[@0, @(4.0/9.0), @(4.0/9.0+5.0/18.0), @1.0]; + bounceAnimation.duration = 1.0/3.0; // the official bounce animation duration adds up to 0.3 seconds; but there is a bit of delay introduced by Apple using a sequence of callback-based CABasicAnimations rather than a single CAKeyframeAnimation. So we bump it up to 0.33333 to make it feel identical on the device + bounceAnimation.timingFunctions = @[easeInOut, easeInOut, easeInOut, easeInOut]; + + if (!presenting) + bounceAnimation.values = [[bounceAnimation.values reverseObjectEnumerator] allObjects]; // reverse values + + animation = bounceAnimation; + } + else if (type == SMCalloutAnimationFade) { + CABasicAnimation *fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + fadeAnimation.duration = 1.0/3.0; + fadeAnimation.fromValue = presenting ? @0.0 : @1.0; + fadeAnimation.toValue = presenting ? @1.0 : @0.0; + animation = fadeAnimation; + } + else if (type == SMCalloutAnimationStretch) { + CABasicAnimation *stretchAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + stretchAnimation.duration = 0.1; + stretchAnimation.fromValue = presenting ? @0.0 : @1.0; + stretchAnimation.toValue = presenting ? @1.0 : @0.0; + animation = stretchAnimation; + } + + // CAAnimation is KVC compliant, so we can store whether we're presenting for lookup in our delegate methods + [animation setValue:@(presenting) forKey:@"presenting"]; + + animation.fillMode = kCAFillModeForwards; + animation.removedOnCompletion = NO; + return animation; +} + +- (CGFloat)centeredPositionOfView:(UIView *)view ifSmallerThan:(CGFloat)height { + return view.frameHeight < height ? floorf(height/2 - view.frameHeight/2) : 0; +} + +- (CGFloat)centeredPositionOfView:(UIView *)view relativeToView:(UIView *)parentView { + return roundf((parentView.frameHeight - view.frameHeight) / 2); +} + +- (void)layoutSubviews { + + self.backgroundView.frame = self.bounds; + + // if we're pointing up, we'll need to push almost everything down a bit + CGFloat dy = self.currentArrowDirection == SMCalloutArrowDirectionUp ? TOP_ANCHOR_MARGIN : 0; + + self.titleViewOrDefault.frameX = self.innerContentMarginLeft; + self.titleViewOrDefault.frameY = (self.subtitleView || self.subtitle.length ? TITLE_SUB_TOP : TITLE_TOP) + dy; + self.titleViewOrDefault.frameWidth = self.frameWidth - self.innerContentMarginLeft - self.innerContentMarginRight; + + self.subtitleViewOrDefault.frameX = self.titleViewOrDefault.frameX; + self.subtitleViewOrDefault.frameY = SUBTITLE_TOP + dy; + self.subtitleViewOrDefault.frameWidth = self.titleViewOrDefault.frameWidth; + + self.leftAccessoryView.frameX = ACCESSORY_MARGIN; + if (self.contentView) + self.leftAccessoryView.frameY = TITLE_TOP + [self centeredPositionOfView:self.leftAccessoryView relativeToView:self.contentView] + dy; + else + self.leftAccessoryView.frameY = ACCESSORY_TOP + [self centeredPositionOfView:self.leftAccessoryView ifSmallerThan:ACCESSORY_HEIGHT] + dy; + + self.rightAccessoryView.frameX = self.frameWidth-ACCESSORY_MARGIN-self.rightAccessoryView.frameWidth; + if (self.contentView) + self.rightAccessoryView.frameY = TITLE_TOP + [self centeredPositionOfView:self.rightAccessoryView relativeToView:self.contentView] + dy; + else + self.rightAccessoryView.frameY = ACCESSORY_TOP + [self centeredPositionOfView:self.rightAccessoryView ifSmallerThan:ACCESSORY_HEIGHT] + dy; + + + if (self.contentView) { + self.contentView.frameX = self.innerContentMarginLeft; + self.contentView.frameY = TITLE_TOP + dy; + } +} + +@end + +// import this known "private API" from SMCalloutView.m +@interface SMCalloutBackgroundView (EmbeddedImages) ++ (UIImage *)embeddedImageNamed:(NSString *)name; +@end + +// +// Callout background assembled from predrawn stretched images. +// +@implementation SMCalloutImageBackgroundView { + UIImageView *leftCap, *rightCap, *topAnchor, *bottomAnchor, *leftBackground, *rightBackground; +} + +- (id)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + leftCap = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 17, 57)]; + rightCap = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 17, 57)]; + topAnchor = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 41, 70)]; + bottomAnchor = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 41, 70)]; + leftBackground = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 1, 57)]; + rightBackground = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 1, 57)]; + [self addSubview:leftCap]; + [self addSubview:rightCap]; + [self addSubview:topAnchor]; + [self addSubview:bottomAnchor]; + [self addSubview:leftBackground]; + [self addSubview:rightBackground]; + } + return self; +} + +- (UIImage *)leftCapImage { return _leftCapImage ? _leftCapImage : [[SMCalloutBackgroundView embeddedImageNamed:@"SMCalloutViewLeftCap"] stretchableImageWithLeftCapWidth:16 topCapHeight:20]; } +- (UIImage *)rightCapImage { return _rightCapImage ? _rightCapImage : [[SMCalloutBackgroundView embeddedImageNamed:@"SMCalloutViewRightCap"] stretchableImageWithLeftCapWidth:0 topCapHeight:20]; } +- (UIImage *)topAnchorImage { return _topAnchorImage ? _topAnchorImage : [[SMCalloutBackgroundView embeddedImageNamed:@"SMCalloutViewTopAnchor"] stretchableImageWithLeftCapWidth:0 topCapHeight:33]; } +- (UIImage *)bottomAnchorImage { return _bottomAnchorImage ? _bottomAnchorImage : [[SMCalloutBackgroundView embeddedImageNamed:@"SMCalloutViewBottomAnchor"] stretchableImageWithLeftCapWidth:0 topCapHeight:20]; } +- (UIImage *)backgroundImage { return _backgroundImage ? _backgroundImage : [[SMCalloutBackgroundView embeddedImageNamed:@"SMCalloutViewBackground"] stretchableImageWithLeftCapWidth:0 topCapHeight:20]; } + +// Make sure we relayout our images when our arrow point changes! +- (void)setArrowPoint:(CGPoint)arrowPoint { + [super setArrowPoint:arrowPoint]; + [self setNeedsLayout]; +} + +- (void)layoutSubviews { + + // apply our background graphics + leftCap.image = self.leftCapImage; + rightCap.image = self.rightCapImage; + topAnchor.image = self.topAnchorImage; + bottomAnchor.image = self.bottomAnchorImage; + leftBackground.image = self.backgroundImage; + rightBackground.image = self.backgroundImage; + + // stretch the images to fill our vertical space. The system background images aren't really stretchable, + // but that's OK because you'll probably be using title/subtitle rather than contentView if you're using the + // system images, and in that case the height will match the system background heights exactly and no stretching + // will occur. However, if you wish to define your own custom background using prerendered images, you could + // define stretchable images using -stretchableImageWithLeftCapWidth:TopCapHeight and they'd get stretched + // properly here if necessary. + leftCap.frameHeight = rightCap.frameHeight = leftBackground.frameHeight = rightBackground.frameHeight = self.frameHeight - 13; + topAnchor.frameHeight = bottomAnchor.frameHeight = self.frameHeight; + + BOOL pointingUp = self.arrowPoint.y < self.frameHeight/2; + + // show the correct anchor based on our direction + topAnchor.hidden = !pointingUp; + bottomAnchor.hidden = pointingUp; + + // if we're pointing up, we'll need to push almost everything down a bit + CGFloat dy = pointingUp ? TOP_ANCHOR_MARGIN : 0; + leftCap.frameY = rightCap.frameY = leftBackground.frameY = rightBackground.frameY = dy; + + leftCap.frameX = 0; + rightCap.frameX = self.frameWidth - rightCap.frameWidth; + + // move both anchors, only one will have been made visible in our -popup method + CGFloat anchorX = roundf(self.arrowPoint.x - bottomAnchor.frameWidth / 2); + topAnchor.frameOrigin = CGPointMake(anchorX, 0); + + // make sure the anchor graphic isn't overlapping with an endcap + if (topAnchor.frameLeft < leftCap.frameRight) topAnchor.frameX = leftCap.frameRight; + if (topAnchor.frameRight > rightCap.frameLeft) topAnchor.frameX = rightCap.frameLeft - topAnchor.frameWidth; // don't stretch it + + bottomAnchor.frameOrigin = topAnchor.frameOrigin; // match + + leftBackground.frameLeft = leftCap.frameRight; + leftBackground.frameRight = topAnchor.frameLeft; + rightBackground.frameLeft = topAnchor.frameRight; + rightBackground.frameRight = rightCap.frameLeft; +} + +@end + +@implementation SMCalloutBackgroundView (ClassicEmbeddedImages) + +// +// I didn't want this class to require adding any images to your Xcode project. So instead the images needed are embedded below. +// + ++ (NSString *)SMCalloutViewBackground { return @"iVBORw0KGgoAAAANSUhEUgAAAAEAAAA5CAYAAAD3PEFJAAAAHGlET1QAAAACAAAAAAAAAB0AAAAoAAAAHQAAABwAAACkF8Y1LgAAAHBJREFUGBlMy6ENQyEARdGXJh2CBEZAgAABhoQgEASDQBCWYqy3wt/lt80XFfe4CwCvT3gjpXThnEPsvYm1FjHnJMYYRO+daK0RtVailELknPndiBjjQwiB8N4TzrkHay3xwxhDaK0JpRQhpfxHCMEbAAD//2TbkE8AAAA9SURBVGOQlJQ8w0AJIScnd4ZBQ0PjDIOysvJdBiCIARFhIMIPRLiACEsQoQMiFEGEBIgQABFcIIIVRDABAL6ePTfutWY6AAAAAElFTkSuQmCC"; } ++ (NSString *)SMCalloutViewBackground_2x { return @"iVBORw0KGgoAAAANSUhEUgAAAAIAAAByCAYAAAB5lADlAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAHGlET1QAAAACAAAAAAAAADkAAAAoAAAAOQAAADkAAAD3bjNTjgAAAMNJREFUOBGkz72JhGAAhOGpwyZUVESFVfAPFFRcFfypwmJsa4KNtxaPucAvuuiCZ3jTwX3fkN/5I7Iso2Acx4/guq6v4DzPj+A4Dgr2faeY2LaNgifWdaVgWRYK5nmmmJimiYL3+03BMAwU9H1PMdF1HQVt21LQNA3FRF3XFFRVRUFZlhQURUFBnucUPJfTNKXgidfrRUGSJBTEcUwxEUURBWEYUhAEAcWE7/sUeJ5HMeG6LgWO41Bg2zbFhGVZFPwvfgAAAP//7zgpOQAAAGxJREFU5cYhCkJBAEXRqyAYLJOECTLFaDXafjNZDIKgLniWNL73eXxwDYZzudRau/HP01rrxjKllG4sA3yCt8Z4BU+N8QjuGuMWXDXGFFw0xjk4aYxjcNAY+6BojF2w1RibYK0xVrMxBjbnZ75mdyKsdyBPxAAAAABJRU5ErkJggg=="; } ++ (NSString *)SMCalloutViewBottomAnchor { return @"iVBORw0KGgoAAAANSUhEUgAAACkAAABGCAYAAABRwr15AAAAHGlET1QAAAACAAAAAAAAACMAAAAoAAAAIwAAACMAAAKHOsNB2AAAAlNJREFUaAXsVVmKAlEMDANzCEWvIC644IILorjgAvrhh+iZxGPlCnOXMQ3VpMN7PXarMy3MR1FJpSovtB8SEX28AejzdmS2MRwOv5JiNBolyiT123voer3yb+JyuSR+j87nM1ucTicWQEcNhi7s88LjymDmY2TAdDweOeugw+HAWQft93ve7XYsnBZJ8tZre9cNtNlseLvdsrCFT9c+7fHVvjfu9dNqtWLBcrmMsNWlX6/XEQ8yLi80FyMn7KolA11qms/nrLFYLIJeGDXm6O1sNpuFO+CxGfSWkUUODJ/MaTKZ8HQ6DSA1oDWp43yYIWt7u8vu03OdhY/G4zELbv8KAft66M9k+6ZvN93+ghgYDAZhHadhpvmRrN6DWu+jXq/HQL/fZw3RpbcMD3KYwysPaA26MGY2Cz/mOkPdbpezDmq32+xCq9UK9U6nE9Yub1JN70Ot37P7qNlsMiBG1MK217NX1vZdajQarCGPo0etGcfBIwwNPjvTHj2D7tOwL3JkvV4PDgTrsEvTc9Q/+eLmdoaearUa34tqtXq3V+9Mm8MOkgUuVCoVFiSZwZ8mK+/oPN4VjbAwjsvlcrAgzuObPSNLpVKJfZAHMNM1tDjWfl3HZTDTfqmpWCyyRaFQYAF01JYx1/yKLGFpljk4Mp/PB18Oh6IHQ3ex9djelYEGr2XMwSQGbULvYwnamUuzHuldPpdms+GRuVyOATH5artAeyWje1unzZJerJfiSDAeQA9GBgxd86PZ4EgsjHsIHh+/Mhs50nfAX+v/Rz7rF3iLL/kNAAD//2Bk4sgAAAQXSURBVO2Va08TQRSGB9TWO2jxUgRapFeioGi8XypGImoA72hQf4IfVDCE+AtrwheDMfBb8H3WObhstvRCNSTa5M10Zs6c95mzuzMunU5Xd7rcTgeE7z9ku57S/0r+W5UcGBioxqm/v7/a29v7V44nfPCL42DMlUqlalTFYrE6NDQULOrr6/tjsMCRHxD88I2y0HeaXIvRai6XW5GWBwcHg0TtrqoBkh8f/MSxGsOy5vSbk954vVWL3iUSiS/a5fd8Pt920DAg+fHBD1/vD4MxwedeeL1UOyu9kl5Lc1q41G7QGoBL+Hlf/OGAx9jclDrTXjNqn0jPJAJmBbrYLtAagIv4eD988YfDmOBz97wm1N6XJqVHEpMseC7QzwJd2c6jjwFcIS/5vQ9++OIPBzzG5q6pg65LN6Xb0rhE0AOJxU+VcKFV0BqAC+T1+fHBD1/84YDH2NxZdUakUem8dEG6LBFUkVjMDh8LdL5Z0BqA8+TzeclfkfDDF3844IELPnfaK6e2IJWkMxKBlyR2dVditzPNgG4ByDtHPvKSHx/88MUfDniMzZ1UJy31Sn3SgMRkUWIX7Iyyj0u8Lw2B1gEkD/nIS3588MMXfzjggQs+1y0dkY5KKem4xCTB7GZYGpOuSnekuqANAJKHfOQlPz744Ys/HPDABZ/b73VA7UHpsEQAwackdleWeBwGytdXs6J6b6vcJP6g5iueJ15inQGSj7zkxwc/fPGHAx5jc3vUQQkpKe2TCOiSeiTKnpV4V85JVySMAtBkMvkp/DFxD4cBmVdsGJD15CFfViI/Pvjhiz8c8Bib61THtEv/d0sEsQt2Rel5DFkpDnRaIB8BLRQKy6reV1r6jGvNtMSG2FgUkLzkxwc/fPGHw5g63fr6+oY00eEnCWQn7OqQxGPgBc5KYdCK+gBMCehDJpNZKZfL32jpM+7nK2qjgOQjL/nxwQ9f4Do2cYU7/CfABzYDOqE1DwX2PpVK/aClLzFekVoGDJiikE2CjgqAA5izblwCatK39BlnnjieQFZquILGtvGobcBaJWukokXFjUgXJb78G9It39JnnHnislLTgEHRDCquVdJ6oJxteWlYolpjEmC09BlnnriWAOtCBgFbg56QObfDoFSQeKRl39JnnHniGvpIYosVNxgdk0GtinIjHJM4SoChYhnf0meceeLqfsVRX+vXfCctwFqZREH3aoyboUuiSj0StwZVo6XPOPPEEZ+QYo8Z84lrG4ZksX5hUG4DjDmE7ToFqFui5YBmnHniiG8aMPCNI99qTEYGarcT1eGmMGCgDIxxq57dIpsO6q28bK6pSm4s+g3K7WCwVAogk1XO4IhtGhDPliCDhb9AraoAGDBQYbAArlXAbUFaVSPAQG9SOK7V/z8B/0J0prY8CNcAAAAASUVORK5CYII="; } ++ (NSString *)SMCalloutViewBottomAnchor_2x { return @"iVBORw0KGgoAAAANSUhEUgAAAFIAAACMCAYAAADvGP7EAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAHGlET1QAAAACAAAAAAAAAEYAAAAoAAAARgAAAEYAAAGukzENIwAAAXpJREFUeAHs2smJgmEURNGKwyRUVEQFFZxAQcUJHKIwGNOqRa87FjuIeovm5y7uVvDwvsKF+n6/otwAxKJDAhLI/DlWTprm87kpN9DpdPqh3ECfz+eXcgO93+8fyg30er1MuYGez6cpNwCy6JD0eDxMuQGQRYek+/1uyg10u91MuYGu16spNwCy6JB0uVxMuYHO57MpN9DxeDTlBjocDqbcAMiiQ9J+vzflBtrtdqbcQNvt1pQbAFl0SNpsNqbcQOv12pQbaLVamXIDLZdLU26gxWJhyg34y0rRX3Y0m81MuQGQRYek6XRqyg00mUxMuYHG47EpNwCy6JA0Go1MuYGGw6EpN9BgMDDlBkAWHZL6/b4pN1Cv1zPlBkAWHZK63a4pN1Cn0zHlBmq326bcAMiiQ1Kr1TLlBkAWHRKQQObPsXLSuEgukots5K8EnjZPm6fN0678udC0z2Ij2Ug2ko1s2q5Vfh82ko1kI9nIyk1p2mexkWzk/9rIPwAAAP//UHDJMwAAB+NJREFU7ZmJdhRFGIULQUkiQiImkYhmWAVEFhERUBxZRDZRkE1W9U0EUV8OHgnv16fv2KeZ7pme6WUmds65pyq136/+qunpCSsrKy9bjc8gtBDHhwjDFmRJJ7IF2YIs50iWdbW1EdlGZBuRa/Jxqz3a7dFuj3Z7tMt6VFiL47R3ZHtHtndke0euxbutLE+h0+m8HFWrq6trJrrwMioH+oVxOtN3LcAcF2IEcmFh4WVRLS4uRpHoTZhmmEmIHHO8FeVB+zBKJ/dZXl7uHYdphJmEiBf7GiUN+vu9qGZmZp5rshdMOK0wMyC+mJ2d/acoj7h9+E2ZYdWDPs0wC0Aclgvtwq8jKJpgGmHmQPw7EVCjMAmPNECeHqveeqK8FU0mmH9OyzEfANHw7I/UvknzGFEX7g/QA9VbD5X3gAz+BE0DzAEQIx/ykgSGV/smHcQp3FGjPN1V/b1YvyhFDMrgBvtYMJ9NamTmQPxLHpLwDMw+7RsGeYyoCzdydFN16GfpViw6GS4T9oBOIswBEDldjjyCA3CGdlt5POPdHPJYhatqmKVrqvsh1o9Kf5IYzGCByuSO0EeTBDML4tzc3HOtGYiOQDzgxeDwiFc82z8ssjhRHi700XcqQxdjXVJ6WboiMeB1iYnYKSZnF3vROQkwh4TImlk7HvCCJ7zhEa94xrs5mEs/ZuGMGqb1jcpQN9ZZpeckBmBQBmcX2C0mJ0KT0fmwSZgDIHKUfYxZM2vHA17wZHB4xTPeu7HMJc2L/8MXGTqh8i+lk9Ip6bT0tdSVGJyJDJQj4Oj0UW8EZgGI3IGsmbUbIJ4MDq94xjsMYAGTLF7hU1X20yGVH5aOSEelY9JxiQGZgN1hUsKdI8COcrckj3oEc35+/oVU+dfJNETmZG6djudalyPRR5m1smbWjge84AlveMQrnvEOA1jApB8rysKeDO1VOdon7Zc+kejAwJ9LTPaV1JUcndeU55jUDnMIiMn7kDWyVk4Ua+9KeMET3vCIVzzjHQbmkcUrfKRGWVpVXUfaKe2WGIyBDZRdI/TZyfPS9xLHpFaYI0BkjayVNbN2PODFAPGIVzzjvSPBIosT5WE5Q++rHK1IH0gfSgzGwExyQCLUCX92kjuFy5kPI8PkIr8rEQ2VHPMxILLWMxJrxwNHF094wyNe8Yx3GMACZfEKC6rsp3dVvjXWYjzANqXbJSbZJRHyROdnEgsC5lnJMLnIM2EuLS2N9T4zCZGx+tyJbOBdiauGU8IGszbWyFpZM2vHA17whDc84hVoeDcHmPRjRVnYlKF3VL451rxSGjPgksQk7NYOiR08KB2V+FSrBWYJEFkra2btjkI84Q2PeMUz3s0BJlm8wowq05pVmTWn/NvxAAzI4O9JhDk715FYCBezYXJxVxaZJUJkzaydgMALnvCGR7wCDe8wMA/SNC/+D2/m6C3VoY0SAzAgg2+R2DFCnzukI/FpZpg8a1UCs2SIrLkj4QEveMIbHg0P7+aQxyq8oYZprVdZUhv0P4MYKLvk6OQYcBlzt1QKswSIbDCnhg1nrayZteOB+w9PeCNo8IpnvCdZkE/z4v+wboDciQEYlN0hlNkxw+RCNkweGQ5ILLi0yBwTIqcjCyJr91HGE97waID2n8/p1atXIU8a0AMwoGE6OpmYC5iFVAazBoh4MMRkFOI58p/HiLpciO7swZQ2AtO/n6cecZ5pPQ+lvEecYSJxbIhDg4waNhyZY0LkqkneiT7OpUAsBLJJmJMOsTDImmE+5c1N/G3Fb3GeFjzOlUciTEYCWSPMB3r9ZZi8CgPig8SdyFdPvoJelS5KZ6XknQhEniD8iFP6cTbEkUHWAPOOANyT7gvgH4h8XEbdREEcC2TFMG8K1m2JFw4AReQpo25iIhEOY4OsCOYVgbou3Yih3VKKAEgZdbRp/DgbYikgS4B5RFD8Dehb5S9IlyTuPqARfYg8ZdTRhraN3YlJiKWBLBHmacHpSuclIg5ol2ORp4y6rkRbNoCNqPWDJQ2xVJAlwDwsIMelkxLvNIm4cxLgEHnKqKMNbenTOMTSQY4Jc7+gHJKOSSekUxLQ+DkAkaeMOtrQlj67pVoecfCXpcyKrA7DlMvYulhvKF0vbZB4GbBRmpPSLzr48WiXtE86KHFcgcXRBRwiTxl1tKEtfRqHCJNKQEYDF4O5TUCAuVPaKxFpwCLqOL6IPGXU0Ya29KHvosQbKH93ZsPYODaQjWRDo80dJhBGaVMZyIIwkz9dEGFE2h7pY4nIQ+QpcxRuV56fBhqHGHkdhX6RPjI6zDGfV7ut0rLEC2IgAbQj7YhFnjLqaENb+tC3sUg0i0ojsjfJYJibBGOLxPEkOoFEtAEsKcqoow1t6UNf7t3aj7P9kdYCMpooH+asQPBbyWaJCAMS0QYwji4iTxl1tKFt1u8rld+JSYi1ghwC5ozAEFlEGEcVUEQc0BB5yqhzFNKn0Ug00Noisjfh65HJpyqfsPzgBBTgEKFAJeKAhshTRp0B0oe+jIFqj8SeL2fqTGU4+QGEeSD4WdNADRVoFmXIAJOPN41BhF3tEekNE4x+MB1Zhkq0pWV4bgvARiE2CjIHqMEYVDp1vdNoQzxeU2ljEZk0nIhORympQaXTZJuJgIiXiQCZhBot6r9j/xo0oKfbT8L/EwlyEsAUXUMLUseyKLR+7UsZpN/A/7eyfwFew4OhAH+vjwAAAABJRU5ErkJggg=="; } ++ (NSString *)SMCalloutViewLeftCap { return @"iVBORw0KGgoAAAANSUhEUgAAABEAAAA5CAYAAADQksChAAAAHGlET1QAAAACAAAAAAAAAB0AAAAoAAAAHQAAABwAAAKS6krCNQAAAl5JREFUSA2klNmKGkEUhs0yM9nIglnctQc3zKioqOCKwQVXFBRUcLnxwvtci88gPkpeIlATEshVSM2rmP9UUo3dajuQi49TVX3OZ3mquk273c50DpPJ9OAID7H2l2MCXYFMfoT1xzouML842MU/gabQ4XAUo9Ho10KhcFcqlbgejWRPIH/10ul0fq7X67/X6/X3zWZzu91umR5VohPQNq/MZvOndrv9a7VafVssFmw+n7PZbKYi50JyTIC1Zz6f78tyufwxnU7ZZDI5iV5CjbsiAXiZy+V+jsfjW8BGo9FJ9iXUh0vwlATAnEwm74bDIRsMBoZICZ2G3MULjN8ASzgc5v1+n3W73QN6vR4j6BlyxUUiCTVT7uIdxo5QKMQpqdPpaGi1WmIuI3KFRP6V55iLXSAqgUCAUyKOmDWbTdZoNESUY5oT+xJqKP0VM7ADL06HU0GtVlOpVqtMIteRK3ZC/XgCqKFvgRMEvF4vp4JyuWwIcg8k77HmBiFFUXilUmG45oaQRJ4MNfUV+AA84KPH46H3hBWLRZbP50WUY5pLkKuRvMbcAhRwQxIqwqUzBLlCQsdLt1QjcblcnASZTEZDNptV5zQ+JbnGgxuSUFI6nTbESBLGZ4DTLlKplGBfJtconpVQId4hVUTj/flZCb5oPBaLsXg8LkgkEuwYhjux2+0cF06VkExKZaS1sxJcOOb3+0UxFR7DUGK1WjlJcEqMYjAYZPg8sEgkouGsxO12M5wSQ380kdYk95KQwIj/kthsNiE3lFgsFk79oGRZIMcy0g7vJUGDVZEslpGe/QEAAP//KqClBgAAAfBJREFU7ZTRatNQHIfjdFaj1El1prW2Sbti2aZeKEMFB+pAEFREFAa79d5n8YF8gkzUi93M7VXq9x08I82y7QH04iNpOP34/37nJEmSJAuwCCksQQYjuJdl2cFgMCh7vV6g2+2WVXzub9aeLan+sen+v2S+3H+12Hioms7IWZ2ss+AwntiTBKdJCk6hkr08z3f7/f7cca8L44m9wM1liO9OkHQ6nW/j8fjncDgsFZ0Uqy65xoNbkMNamqafEexPJpPvo9GoNFoTrE3OgZNcgjYswxBWYaPdbn9lmt/T6fQH7EJZh3XHJDd4dgfuwkPYbLVaX4jyqyiKQ4QHdVgTJOe5tuAqdOA2rMADeAov4DW8h0+wDTsVjiQXeXgFroMfJstdg0fwDLZA0Tv4AB9BoQRJ/Lq5Q/ZyE/owgfuwAYpewitQ9gbeBmazGdfwdbPcGClOY8F2o8iJjLYJz0Gh020lfyXukL0YKU5jN11Q5ERGsyPLdrLH8CRQkRgpTpNybyxF9mM0O1oBJ1sFpeuBmsRp/PIbK4qMZkfK3DW33+lyUFyEOKeIjOa2O5UyJ1O4DJ5sxdmRpEFkNDvyJCtz+6NQqa+I79rSnKQmsiPjKTOiQmMqjWLl6TFJReSOibKqUGlE+WKjRFEVFkZh9RrlC38A3S8C8jPZQY0AAAAASUVORK5CYII="; } ++ (NSString *)SMCalloutViewLeftCap_2x { return @"iVBORw0KGgoAAAANSUhEUgAAACIAAAByCAYAAAA2yQM1AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAHGlET1QAAAACAAAAAAAAADkAAAAoAAAAOQAAADkAAARX3Ik1YgAABCNJREFUaAXsmFlLJGcUhjtOJhOTSWbSMTpRMyhpNdqJCyruG2644L7gCoqKInihqFeCeqP3gqLxLpAfkZ8QCMelmUwWk/wT875FTlPT0zpV39cTTFB4OFZp9fd4zqmvThm4vr4O3AXuhAQTcS8S2w5vLSNVVVUZDQ0NM01NTcfge/BTY2Oj3ETCRerr60uw2CkkJB49PT0X/f39lwMDA6+QMJHS0tKHkNjUxVtbW2Vvb+/q9PT0L/DnycnJH8fHx1dHR0dRDg8PrxRrkUAg8E5xcfFTSESzsLOz89vBwcHvEPlla2vrxebmZmR9fT2ytrZ2ubq6GhdjEQqQzMzMZGThO2aipaVF9vf3f93e3v4Zi0aWl5cv5ubmzmdmZs6mp6eFTE5OxsW3iAr8E5Pq6uq2kA1hKXZ3d19ubGxElpaWnMW56MTEhCd8ibgkkvB9Unl5eZgSBAIvkPbIwsLCOf7yMz8SlPUsEiuB4we1tbUnQLq6uoQS8/Pz51NTU2fj4+PiF08iMRIPcPwus0EJ7A+ysrJyubi46GTCr4D+/htF4kng3MPq6uqVmpoa6ezsFEhcsCH5oWNjY0Z4FXF6gpmgBHhUWVn5LWRkcHBQZmdnz9ETZyMjI2LKrSJY0LlFESnCkjgSiMmQ+IEiXJjNyTg8PGyMF5HXJCDyGM+SH4FTBpbERoLX3iiCxZgNd0new/H74EPwhBIqwr4YGhqywouIuyQfQOJjEKyoqBAyOjrqwF6xwYsIG5TZSAaPwVPwGW5fIVqSvr4+sSGuCBbSssTLxqf4+bNYkd7eXrHBi4g7G59AIhVk/NsiLMsjoL3hZAPHz1VEmxQDj9hwW0bcZeGd4vQGYjrIxiAkBNOWA583Ntwk4t47tEm1LJkQCamINii3ehveJKL98REWD4Jn4DnILSkpEaINaiPBa72IuPvjc0hkga8wHgrRvmhvbxcbXhPBInrruhv1Cc6nAKc/EPOLioqEdHd3O7S1tYkNXkTcjZoBiS9BgYpoSTgq2uBHhPsHG5Ui4cLCQiEqwsHZhttE+MjnQ063dRUJ4dzX+BLS0dHh0NzcLDZ4FeGtmwa+AI5IOBwWon1x06uk1/OmIt8UFBQI0b7QNzzT+J8V4WaWA6IZ0QbV9xvT6DcjUZH8/HwhfJ0gnOhtMBbJy8sTos3IQdoGY5Hc3Fwh2pw2ErzWWCQnJ+cVER2mTaOxSFZWllBGm1OHadNoLIL/i0goFIo2qE5sptFYJDU11RHR3jAV0OuMRVJSUoTlUZGysjKxwUokLS3Nedtjg+roaBqtRJgVziV3QoTl0fnVJlpnhCLZ2dnOnqJzrElMiAhl0tPTnebljKJjpJ+YUBHKqBC3fz9Sb0VEhfzEe5HYbN1nJGEZCQaDQnjr6u0b++F+jo1L878V+RsAAP//Pedk8QAABFZJREFU7ZndclNlGEYDNQUloWlMCU1CGn6qAqIowjgoyp+joDhqwb/6g3oDHnkH3oLjoWceeOKMjgeeeAEe9JLqWkle83W7k+4QZso46cyaZDfdey+e9/m+NqG0vb1dSimVSvtgP5ThIFRgGZrQhXU4V6/Xt6TX6/VptVpbs7BDQiG+5iI7UpknkhZ13hFW3I5+zBOZJ5KzC887kv29NE9knkg2gezxvCP/y0T+Xl5e3lpbW9vbv1lrtdpfj4QIEj8r0ul0+om02+29+Su+Wq1+r8jq6mpfpNvt7o3I4uLihiIrKyt9Ed/fZFfCNMfT7iPH+Cv/FJyDS0tLS7+kqVjcaW6e/uxMIqSyqYjE6nlQmQcVeZZELsIVuvJjjGgWmaIiNW56BDrgaP4V4fktlvJvWRk7Y4GLrqZJIo9xkwNwCFKRkxyfhZfgVbi5sLBwD5lflfGNeaykeINe5HEakRVu2gZFzsAFeAVuwG3YYEw/KSONRmOr2Wz29xmT2U2miMgT3GQJGtCC43AaXoTLcB1uwbtwlwJ/x2r6I4SKPv5HZPgmy89HFmARFDkMT8Iq9OAZOA8vw1V4E+7AB/ARbJbL5W8rlcoPjOx3xP7cTaiIyONcuAp1OAp+WPMUPAeX4DV4A96G9+AefAKfw5fwFXw95Bse88m+Cc8k4qdGisSnRq6c2NQsbPTE8bwFjmcD+qnwGDL3ea5QKhVyg8cxIvs4ydEokq4cCxs9ScfzOt9PU7nL8cfwKSjzBZjO/RwGghNE9nNSLOG0JzGedV53q3cZu3qugV15BxyRMibjmDbhM1AqxJQbsYuIqVjY7HhcxifgNDwPdsU95TqkMo7JzoSQUqaUouTmuLI6GhNJx5OXirusXXkBXEFXIGQsr50xHVeTCSklHw5RcEBeIn6Pr5BxPGkqNY6jKz2eu4Lc8t1XlDEZx2RnLLBCLu2QUuz9IQoOKCCSl0qdCzShA8fhaVDGZByTnbHApqOQ41LqNigW2KcBBUQcUZrKIY7dad3gUhmTOQt2xgKbjkKO6yoodQNuDlFwxDiRzHjSVKK4jiiV6XFsZyywq+k8XAATUuoyKObolBM3wwEFRKIru8m0uGgXTsA6uM+YkDuwUnZIMdO6OETJAZNEMqnEiMqcfAAiGcdkZyzwUWiDQnbnJDgypUzqDChnn8TkBhQUSVOxL6mMnTkMMaojPFfIhCyzUj1QzLSUc4Qp67n7SFaOkxQZJ3OQ19xjKqCQ/5Nhd0wopPytrZhpKSfHErqFRJIRpTLRGfeYGFUqZEJKOTbFGhByCrriRmT/9ZOOOTFNxs4oE6PKCjkyU6qCSdkl5QIlR0y6cd5rnBwykc44oUjJUpuUKBeCSo7Iu1mR73GREFIkMKE0JUttUpGWcmKvdlLkppN+hguGUJpQpBRiIecYY5RKjph0k2lfy0iFYKQ1+XHam83y82NEB8KzXPhhnlt4H3mYN8271iMj8g/zleowQQBJWQAAAABJRU5ErkJggg=="; } ++ (NSString *)SMCalloutViewRightCap { return @"iVBORw0KGgoAAAANSUhEUgAAABEAAAA5CAYAAADQksChAAAAHGlET1QAAAACAAAAAAAAAB0AAAAoAAAAHQAAABwAAAKdevXfpAAAAmlJREFUSA2UlNlqWlEUhredJzpgB41zcAi2JiRiBE0UiwNxQsGACibeeJH7XovPEPIofYnCSmmhV6XJq6T/f3SfHg/xmF58rH22rm+vvfY+Ryml7llwYbzEzc2NWgdy1MMFDxCt3MezXsAU3yZUpVLpyk6hULje2dn55vf7iwvxktAuUhcXF2Ln/Pz8cjab/Tg6OvoTCAS+QPTIJnNZRer09FTG47Ewavg8mUxkOp1+b7Vav91u92dIHgNuXVdlitRoNJJVnJycyNnZ2c9YLPYVyc9WidRgMJBVDIdDAZcHBwe/IHhpEfEA2HSjGnV8fCxO9Pt9yWQy10hwA4qeAvaI25pLOp2OdLtdA47t9Ho9SaVSV0jwgDfgBWB/jGrYYNVut6XZbIo1cqyhNJlMUuIH74Cuhk02tqTq9bpoGo2GED4z4oiNBRKJBCURoKt5jrG5JVWr1YRUq1UTPcdIGU6HkijwAfZGb8noiyqXy+IE5dFolJIECIC3gFt6AtgXF6+9OFGpVCQSiVCSBCHwHixLDg8PxUqxWBTCOUYuEA6HKfkIwuADeAV41PP7goskTlC0kHxCkm7u6yVJPp+XXC5nYB3rOS4QDAZZiV3C12B+zNlsVpyg2CLZRCKPmZX8k+zv74vGKtNzrAifA1aSAusleEf4nphSjileK0mn03Ibe3t7QnZ3dwVfOOdKrH/WSXqOERdNfD6fs4QrrSIej/OirZdsb2+LFbz2srW1ZSTjVIzo9XqdK0HT2DgT7N8Y6xgKhWSthH924s6SjY2NlaL/klCkYWV6zL54PB7nnmC/ZoJO1JG/3UXyFwAA//9HuzCQAAAB80lEQVTtlc1qU1EURk9iNXqVqERrEmNykzQY/B0oooKCPyAIbRGpIDh17rP4QD7BragDJ9q+SlwrZsd7NRQFhx0szulhf9/Z+7uHJnU6naLb7RauZTyTfr9ftNvtvZTSdRhBG85ABkehnsrCVftDk2q4ZnSYSTWT//LYwoSA93mZ1+DfX2yv1yvyPN/F5OvCZMj6d8/eDjQYDAbFeDz+3Gq1PqwwOcHZGtST72AVo9GomEwmHzH6lmXZW4qvQg4X4DT8MplOp8UKdjn7RBffm83mewR34AoMYB2acBzspJYo3Pud4XC4z0hfGo3GO4oewi24DJfgHFRNOHhT4jX7V/ACnsNjuA83YQMuQgtOQQOOQA3mIoU78BK2QYOn8ABug3nElznL/iQcg6XJFn/IJih+Bk9AA7O4ARPowXlwFEP9+V9t0Yk3isJHYAaOYAcamIWB+j7sIkZZY1+fzWYsKd1bcJfVmw3RDBzBDjTogFlEF8tRwsTnLIr8jN68AWbgCHYQBhl7A513wVoLE4slB2/1M/oVFJuBI9hBGJiFgdZhaWKx+BLXQaE3h9gMDNIO/jCITvwNEZ+yN4pCP6NiX6YZOEKlAw3CxDYtDoEib1XozWXxcoQwCBMLo1hBELfOhZzXpCyOPefzgCysFCuQKDxo/QHd3ALyX+9lLwAAAABJRU5ErkJggg=="; } ++ (NSString *)SMCalloutViewRightCap_2x { return @"iVBORw0KGgoAAAANSUhEUgAAACIAAAByCAYAAAA2yQM1AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAHGlET1QAAAACAAAAAAAAADkAAAAoAAAAOQAAADkAAARyl43hJQAABD5JREFUaAXsmFlLa1cUx3eH27m9rbXaem1R6lCHOqDiPOGEA84DjqCoKIIPivokqC/6LijavBX6IfoRCmUZE25vB9v7Tez/f3DJIU002TvF2+LDj5UEcvYva629zzox19fX5lXglZBgIh5FItvBtLS0SCxaW1t/Bj+As+bm5vna2tpnkRdI1nszPDwc8jM0NBTq7++/xMISDUgHmpqaypMloNcxJycnV8rp6emVcnZ2dnV+fv5nIBD4C7w8PDy86ujouJWDzE5FRcUTvZBrNBsbG6FobG5uhra2tsI7Ozvh3d3d5xD59fj4+I/9/f3fNVOQCZSVlX1sjHnNWWRmZkaiMTc3J2R+fv5icXExuLa2dgm58N7e3i9HR0e/tbe3a3a+z8zMfJcyLkJmenpa4oGylFpdXQ1ub2+HDw4OXrBUyIo0NjbuQuJ1lbERiluEspRBli6Wl5eDKGcYQs8pQqqqqopuZG6FEimXmZqakkSZnZ29WFpa8mR6e3uloaGBnEPkDVsZKxGKMzMrKyvB9fX1EM4ZT+YmK2/6hOLuGzM5OSk2UIY9A5nLnp4eqa+vl7q6unVIPAEJy5jx8XGxBT1zsbCwEBwZGaGE1NTUfAeJt30y7BevZ+7rFzM2Nia28AewRIwUAT9iYW5lldGeubdETiL8ASwRS4v7EPkJEh/EkrkrK2Z0dFRc0P66ERFIPAXvg3fAW4D9cm+JDOvrwsTEhJDq6moPLJoCPgLvgX+UKFZWzODgoLig/YWty0ONGfkM8P6jJfJnJeY9yQwMDIgLUUQ+h8SnIKGs/BsizyCRBj4B/qzc7qBo5TEYgsQFbXRfab6CQLSsaNNGLY/hvcIFTHRCMCR5QCIbZADtFe4gf9NGF+Hx7II2uk8kBwtngsjy8Oj3yhO1NC4S/K42enl5uRAslge0PNzKHwKettw9sUW6urrEBe0vjIxCsNg3IAt8Afy7526Rzs5OcaGvr09IaWmpBxYvANonqXjNk1YPt5gNazjuuaCl9YkUYuGvAbdxZMPGFuEQ7IKKlJSUCMHiHBkpog3LU1Z3TmyRtrY2caG7u1tIcXGxBxYtBv6do8c9b4LcOVHnkzsfOWM9ivo/1/4qKioS4hP5Eq/TgZ6wd4vow5Jt1P4qLCwUgoW/BczIf1REn0tsozZ6REZykREeavGXhtO3C3yUIAUFBR5YnKVJXORm6NXhN+GojZufny/kwUS0yfPy8oRYi+jQaxv9Irm5ufYiOvTaRm1ySmRlZdmL6GRlG7XRc3JyBP+TPJyINjtF0tLS7EUqKyvFBRVhWVJTU+1FdMSzjdrk6enpDy/CWYTZcMqIzpouUcviJKKzpk3kAZadne1tW+eM6IiXSOTcwSxkZGR4MSkZiVeAizMDKkCJpIroBW0jxZKSEVsB/d6jiGZC42NGNBMaNSMpKSlCrAcjvaBt/N+J/A0AAP//+DyM3gAABEZJREFU7ZnLblNXGIVNXAdaYmIbG+M4JAZKgd6g3IQo94u4tiqUXmgLpe0LdMQb8AqoQ2YMmCC1YsCEB2DgR0q/z+JHm01ixwQIgxPpk30S+6x11r/29iWlmZmZ/kro9Xp9aTQaA0ql0hewA+agDXWYgnVQgQlYs7CwUEoprcSEzy2M5AkWiRSJ5Ankx0VHikTyBPLjoiNFInkC+XHRkSKRPIH8+L3qyPz8fL9er/ue9RnvR1fvPWsYqdVqT1fFSLfbHbx5np2dHSRCKg9Wxcjc3NzASKfTGRipVqt3V8VIFLXVag2MTE5Ofv/OjdgLjUQa09PTDzFx6LmRj7ndAm/3A1aYiJK6Ykjj13dqJDURI6Eb/2DiGByEz+HtJOLqiGI6Ds2ECZbsvwhfhNzILL/bBDUY/dk3CrfcWzvhB27HgYlH5XL5B4TOwlE4AJ/BdkiNrOd4LXwAi38IH2XAJNwn2u12v9lsxn7RZxz3Oamr5BKcga9hP3wKGulCC0xktBGvbBxYHY8p5h1Ofh2+BcdyGo7APtgNW2EGmjANH8HwREaZQPgJI/hvamrqXqVS+ZsTujp+gmvwDZyHk3AY9sIu6EEHNsIG0MgklGEi/V4k7vP70l9D+JO/yR/wO9yEG2AvvoPLcA6Og3vIl/AJ+CXNZmhAFT6EkUZCLL9VXG5DmIg07IZjuQCnIfphUWPpumLi2yKN+G3R0ERSwds8OEUDt8AkfoGfwW6kaZzgOB3LVo7tR17UMPLK11aOxx+FchSW38AUHIe9CBNXuG83ToFpHID0fYhjSfsxtKhhRCHxilMUDwN2wnGYRJhwJO4ddmMPuFq2QRfysbzoB39bMhGvNPiR+6KwmICrQwN2wnKahCaOgSP5CqIbUdI8jRjLBI9d0ohCwVXui8Ih7hLVgMV0hTgOk9DEPvC1xZXSg7QbbuuxWpbcUdPla9SBgoE7puImoAFTsJh2wnGYhCZ2ggV1S29DA2LvsBsj04iOKJLi64acAcVPgmPQgClYTDvhOEwiNeFI3EnXQ57GkmMJI8d5UqCgGL3CR0BxE9gPe8HVYTHdL3oQSWiiBjGSZacRRhQJDnJfvGqF7YDi7pgm4Pa9A7aBxbQTjmOkCR6zaEnTjniFgTMXRX0V9coVdwTbwTFowCW6GVpgJxxHnkQUdOhIUiNeoTGnKOpVK9wDxR2BCWhgE0QKFjM6EePQRBkGJrgdmkaMRpEtCQqKV61wB0LcBDRQBw2Ygq+s6+C1TYQRZ5zi1YqiTVDY+BW3jKkBV4YG3DkrYApjJZGORoEUxQJnr3AVvHpHYAK5gXQUyx5HmIhEFMhRMERDOMTTBBY1wHNHdiI1EUacb45igbFH9MYf4jECE3itFFIznGMwWwVSFAti7nEbwi/EeezYCaQmIpH0xMPur1EwJT/ZSo4578snT49XcuJxn/vSfxrHffKbfHxhJE/zfxa16jD5HvXsAAAAAElFTkSuQmCC"; } ++ (NSString *)SMCalloutViewTopAnchor { return @"iVBORw0KGgoAAAANSUhEUgAAACkAAABGCAYAAABRwr15AAAAHGlET1QAAAACAAAAAAAAACMAAAAoAAAAIwAAACMAAAQYDCloiwAAA+RJREFUaAXMVslKHFEUfSaaaPIFunDaulJj2/QQBxxwVtCFC9GFCxVRUHHAARVx1pWf9QKVNCGb5FvMPUWf5vazqu0qFVwc7nTuvaeedr0yj4+P5qUwxlQoVCq/4qWz0R9boBLyQXwfzc3N31paWn7CMpe3/kPEFRxLZF4gxX2UuLKpqSkxOTn56/T09DcsYuQFqJMb62Qji5SFOBUs9cWJ/dTY2JiEsPv7e+/s7OwHLGLkURdosZGFRhIpyygQS6sE1Q0NDampqakchMkpWgIx8qiDl+ejDw8YSWjZIjE4vwCLcDrV9fX1aQi5u7vzBZ6cnBREQiyFggd+vi+y0LJEynBXYI0szsif1BcIccfHx0+APB4APPBlTk0coc+KDBM4MTGRu7299SDk6OgoFKiDB35coSVFhgkcGxvLXV1deRB3eHhoDw4OiixyGjjlm5sbD31xhIaKDBM4Ojqau7y89AXu7+/bvb09C/sc8EDoQ39UoYEiwwQODw/nLi4uPJzc7u5uZKAP/SMjI5GEPhEZJnBoaCh3fn7uQdzW1pbd3t72resjZg4cgnn0Yw7mlXuiRSKDBNbV1WUwUF4p3s7Ojt3Y2CjC5uamH8NqHzzmXIs5mIe5mC97S/7qpV64svQt8lnyX2pra7MDAwO+QCxaW1vzsb6+bgk3FxSTqy3myS/fw3zswT4B9uI9qq9S6PJvDtweeEGDhKf6Ko3f+/v7c/LL9DB8dXX11YG5mI892Ie9+f3QAT3QVWV6enr+uejt7f07PT39R14j3srKil1aWirC8vJyUezW3bgUH/OxB/uw19WC2Dw8PNggXF9f+0IWFxftWwMPhX1BOpAzCwsL1sX8/LwFmKdPyzxsGJecoB7Wwix7aM3c3Jx97zCzs7P2vcPMzMxY+ae1sHERpd/lunGQBiOfUVa+CS2si7C85mlOmB+2o1y+GR8ft4Bc/EXWzSOWz60iDnuCuMwFWfbBBvnoYR6+kY8GqyGXvx/D0medsVuT660wgxy3h7Fr2cs+WvJQN3It2cHBQR/wCZ2DX4rHGnvd2J3lztN13Uue6evrs4C87X0bFjP/mtbdGTYb16Iluru7C36pHGvavqRXz6Gv55lsNmuJrq4uq4E8YteSwz7WycUCnWMeljW3l3zWdY/JZDL2vcOkUikbhGQyWcin0+mCH8SNmtPz6Ot97jzT2dlpCRDpw7qxrr2l7+41iUTCamA5Y/raUhw5sMyR59Y0R9eYD8txXpHIjo4OXyCtbg7K6Tr953il6m6NsWlvb7floq2trWyunhm3jzMMBgShtbXVAlFq5MfpxR7dz73I/QcAAP//R6Pt0AAAASZJREFU7VK7asNAEBwCblKltISkImrUWEhl+tQuU+WT7xfyL94TjNksdzIkZ7yGMwyzj9m9YWWs6xpuYVmWm5rcjhKzmOc55BAfYE/HrO2x1ut4b4Y9rY8x+r4PFl3XhQjWGVtmX/M9ZsGlnnkz2bbtdjkaZU5mPcVWY/PUDGvUWmafjCjQIuY5joO2l6pZTcxTulTNzl5NNk0TiCjKxXaB1sYZndv4r7PQi/VSmiTzAeZkzpBZ1/zf2c0kF+49RE2O7zn7y2TOwKPr1WSpL1AvWS9Z6gKl9tT/ZL1kqQuU2oNhGIJ3YJqm4B0Yx/HHOyC/7ycAvsSkd+AsJr0Dn2LSO/AhJr0DJzHpHXgXk96Bo5j0DryJSe/Aq5j0DhzEpHfgRUy6xgX1iUkAQX47jAAAAABJRU5ErkJggg=="; } ++ (NSString *)SMCalloutViewTopAnchor_2x { return @"iVBORw0KGgoAAAANSUhEUgAAAFIAAACMCAYAAADvGP7EAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5QUY0RkNERjZENDMxMUUyQTAzNEREMUIxRjIzOEVCNSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5QUY0RkNFMDZENDMxMUUyQTAzNEREMUIxRjIzOEVCNSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjdFQUM5NTk0NkJGQjExRTJBMDM0REQxQjFGMjM4RUI1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjlBRjRGQ0RFNkQ0MzExRTJBMDM0REQxQjFGMjM4RUI1Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+zk9a9AAABhtJREFUeNrsnclO41gUhm3HDGEo5jGAQLwDsxjFICR2JVFVza4fAVFdD9H1ALxA9yPAhg0S6170mnmeCVMSyNDnt3LT7jSIQJzEgf9IVkJw7OuP/5zz3+sAeiwW0xjph0EEHwTkzMzMl+np6W8EmSZEKT2/GYax4HaYhtsh1tfXa9jcDtOVICcnJ78qiCMjIxVNTU12mL+4ccy6G7q2LqGeT0xMfCkoKPgOcH19faUyPl0AahsbG7eHh4faycmJFo1Gf19aWvpDvSfmgovIKUg7QHwpEGcBsaamRuvq6vIGAoHow8ND1OPx6GVlZZ69vb3AwcGBdn5+rmD+CY5uAJozkDaIuk2JCwri/f195Pb2NhIOh2PYtbS01PPp0yfTDjMSifxcXl5WyozlEqbhFoiiuoXq6moL4t3dXeTm5iYSCoWi2ESVMUD1+/1hn8/nRc3EvnKY+ampqW/2YyWp/P2CTIKoK4i1tbVad3e3BRHQkNJQIwQmaRx7fHyM4XvX19fhlpYWb3Nzs4b32GDquYSZ1dR+AuIsICKdFURswWAwKmkbE4D//sSl4cimS/rrJSUlnsrKSnN3dzeABnR2doaURpqrmpn1NM8ayKcgyuMCurNdiYAIJT53HDQe0zSt5qNgomaim6Nmrqys5ASmkU8QEVAq9sH+V1dX4dbWVivNcSyBPD82NvY1F2mecUUmQxSDPSuKWqirq9N6e3u9AKIgAlIq48EhlTLRze1pfnx8jJqadWUa+QYxDiWhTKhZKRPdvKGhAbU068rMmCKTIY6Pj3+Wxx+A2NPT44134ER3tjeWlFUgDciuzKqqKnN7e9tS5unpaVaVmRGQyRCHh4c/ywX/gF2BEmG2FUTYmnTGgFOhmxcWFloNqKKiwtzZ2QkcHR1ZaS7H/7m6uppxmEY+Q1RpDp9pN+1tbW3exsZGK83FLs0PDg5mPM0dVeRzEOET+/r6EjMWzKGTfWLaioj7zKKiIkuZmE6qNIfPzLQyHQP5HESpW1p/f/9/IL5kcdIJ1EzALC8vT8BUc/NMwnQE5FMQ5SVLiYCourOk9au6czo1U8FEzdza2grs7+8nFjoyAdN4TxDtNTMUCsWQAaiZ7e3tXp/Pp2FMMO2ZqJl6mh3zRYi4mGxBfM60S4pb1mhjY8OqmZlQ5ptBJkMUcFZNhE+0Q1Q1UQae9aUtGU9iocMOE9ZIzc3X1tYcgfkmkE9BlAFbFmdgYCDRWOTREYvjhDLhMxXM9fX1ADxm/LaFIzCN9wzRPp2Ez4R/vby8DHd2dnrhMeM31OblGtKuma9S5HMQYXGGhoasdMZgAVEtyrollDJVN6+urraUqXxmuso0nYIIFdohai4LMFFzenluFWwoUx4CeC4woUwtDtN6C645VZh6istW/4OIBQhAHB0d9YrFgM2wIMJ6ODljcXxObFtpr6ysTChT+UyJNykTUP56y4A6OjoM3KiSkz/mC8TnYEp9NzFusUOBOMzXl465ubm/X9oJJ5ST4YQFXq/XIy/BF4YvLi7CqrHkyuKkY41QM3FtUjMN8b6mdPUCfAu+F2ucku5huTaI42VFLi4urqc6WxBQUXWLVLpfojOjI+bj5yztDai4uFiX6aSnpKTEgFhg5BFQbkrNZnNz8z7FYm3BwtQrGAxalgLPFeh8DCUQZJNciw5hCEQLLNL/NVYIn1wIax88ABSZJZsmM7E3qcLkR58damBE4EyY+WBXqMiPpEjWSKY2FckayWBqM7XzBWQ+rdhQkWw2DCqSXZuKJEgGU5sgaX8YrJEEybk2Fclgs6H9IUgGayRrJBXJGsmgIgmSIAmSQftDRdL+MJjaBOnW1MZv0TOoSIIkSAZBEiRBEiSDIAmSIBkESZAESZAMgiRIgiRIBkESJEEyCJIgCZIgGQRJkARJkAyCJEiCZBAkQRIkQTJSD7OwsJAUqEgXKdLv95MCFemewL9h+pUYHEhtLf6//xgE6RqQ/HN9BOkukGFicAbkIzE4A/KBGJwBGSIGgnQVyCAxOAMyQAxUJGskQTLoIzmz4Vz7Y4Hk6o8DgVsNvG/jQHiIwCFF8i+aOhNMa4J0V/wjwADkbTd31/iGkwAAAABJRU5ErkJggg=="; } + +@end + +// +// Custom-drawn flexible-height background implementation. +// Contributed by Nicholas Shipes: https://github.com/u10int +// +@implementation SMCalloutDrawnBackgroundView + +- (id)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.backgroundColor = [UIColor clearColor]; + self.opaque = NO; + } + return self; +} + +// Make sure we redraw our graphics when the arrow point changes! +- (void)setArrowPoint:(CGPoint)arrowPoint { + [super setArrowPoint:arrowPoint]; + [self setNeedsDisplay]; +} + +- (void)drawRect:(CGRect)rect { + + BOOL pointingUp = self.arrowPoint.y < self.frameHeight/2; + CGSize anchorSize = CGSizeMake(27, ANCHOR_HEIGHT); + CGFloat anchorX = roundf(self.arrowPoint.x - anchorSize.width / 2); + CGRect anchorRect = CGRectMake(anchorX, 0, anchorSize.width, anchorSize.height); + + // make sure the anchor is not too close to the end caps + if (anchorRect.origin.x < ANCHOR_MARGIN_MIN) + anchorRect.origin.x = ANCHOR_MARGIN_MIN; + + else if (anchorRect.origin.x + anchorRect.size.width > self.frameWidth - ANCHOR_MARGIN_MIN) + anchorRect.origin.x = self.frameWidth - anchorRect.size.width - ANCHOR_MARGIN_MIN; + + // determine size + CGFloat stroke = 1.0; + CGFloat radius = [UIScreen mainScreen].scale == 1 ? 4.5 : 6.0; + + rect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y + TOP_SHADOW_BUFFER, self.bounds.size.width, self.bounds.size.height - ANCHOR_HEIGHT); + rect.size.width -= stroke + 14; + rect.size.height -= stroke * 2 + TOP_SHADOW_BUFFER + BOTTOM_SHADOW_BUFFER + OFFSET_FROM_ORIGIN; + rect.origin.x += stroke / 2.0 + 7; + rect.origin.y += pointingUp ? ANCHOR_HEIGHT - stroke / 2.0 : stroke / 2.0; + + + // General Declarations + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = UIGraphicsGetCurrentContext(); + + // Color Declarations + UIColor* fillBlack = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.11 alpha: 1]; + UIColor* shadowBlack = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0.47]; + UIColor* glossBottom = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.2]; + UIColor* glossTop = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.85]; + UIColor* strokeColor = [UIColor colorWithRed: 0.199 green: 0.199 blue: 0.199 alpha: 1]; + UIColor* innerShadowColor = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.4]; + UIColor* innerStrokeColor = [UIColor colorWithRed: 0.821 green: 0.821 blue: 0.821 alpha: 0.04]; + UIColor* outerStrokeColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0.35]; + + // Gradient Declarations + NSArray* glossFillColors = [NSArray arrayWithObjects: + (id)glossBottom.CGColor, + (id)glossTop.CGColor, nil]; + CGFloat glossFillLocations[] = {0, 1}; + CGGradientRef glossFill = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)glossFillColors, glossFillLocations); + + // Shadow Declarations + UIColor* baseShadow = shadowBlack; + CGSize baseShadowOffset = CGSizeMake(0.1, 6.1); + CGFloat baseShadowBlurRadius = 6; + UIColor* innerShadow = innerShadowColor; + CGSize innerShadowOffset = CGSizeMake(0.1, 1.1); + CGFloat innerShadowBlurRadius = 1; + + CGFloat backgroundStrokeWidth = 1; + CGFloat outerStrokeStrokeWidth = 1; + + // Frames + CGRect frame = rect; + CGRect innerFrame = CGRectMake(frame.origin.x + backgroundStrokeWidth, frame.origin.y + backgroundStrokeWidth, frame.size.width - backgroundStrokeWidth * 2, frame.size.height - backgroundStrokeWidth * 2); + CGRect glossFrame = CGRectMake(frame.origin.x - backgroundStrokeWidth / 2, frame.origin.y - backgroundStrokeWidth / 2, frame.size.width + backgroundStrokeWidth, frame.size.height / 2 + backgroundStrokeWidth + 0.5); + + //// CoreGroup //// + { + CGContextSaveGState(context); + CGContextSetAlpha(context, 0.83); + CGContextBeginTransparencyLayer(context, NULL); + + // Background Drawing + UIBezierPath* backgroundPath = [UIBezierPath bezierPath]; + [backgroundPath moveToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMinY(frame) + radius)]; + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMaxY(frame) - radius)]; // left + [backgroundPath addArcWithCenter:CGPointMake(CGRectGetMinX(frame) + radius, CGRectGetMaxY(frame) - radius) radius:radius startAngle:M_PI endAngle:M_PI / 2 clockwise:NO]; // bottom-left corner + + // pointer down + if (!pointingUp) { + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect), CGRectGetMaxY(frame))]; + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect) + anchorRect.size.width / 2, CGRectGetMaxY(frame) + anchorRect.size.height)]; + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMaxX(anchorRect), CGRectGetMaxY(frame))]; + } + + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMaxX(frame) - radius, CGRectGetMaxY(frame))]; // bottom + [backgroundPath addArcWithCenter:CGPointMake(CGRectGetMaxX(frame) - radius, CGRectGetMaxY(frame) - radius) radius:radius startAngle:M_PI / 2 endAngle:0.0f clockwise:NO]; // bottom-right corner + [backgroundPath addLineToPoint: CGPointMake(CGRectGetMaxX(frame), CGRectGetMinY(frame) + radius)]; // right + [backgroundPath addArcWithCenter:CGPointMake(CGRectGetMaxX(frame) - radius, CGRectGetMinY(frame) + radius) radius:radius startAngle:0.0f endAngle:-M_PI / 2 clockwise:NO]; // top-right corner + + // pointer up + if (pointingUp) { + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMaxX(anchorRect), CGRectGetMinY(frame))]; + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect) + anchorRect.size.width / 2, CGRectGetMinY(frame) - anchorRect.size.height)]; + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect), CGRectGetMinY(frame))]; + } + + [backgroundPath addLineToPoint:CGPointMake(CGRectGetMinX(frame) + radius, CGRectGetMinY(frame))]; // top + [backgroundPath addArcWithCenter:CGPointMake(CGRectGetMinX(frame) + radius, CGRectGetMinY(frame) + radius) radius:radius startAngle:-M_PI / 2 endAngle:M_PI clockwise:NO]; // top-left corner + [backgroundPath closePath]; + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, baseShadowOffset, baseShadowBlurRadius, baseShadow.CGColor); + [fillBlack setFill]; + [backgroundPath fill]; + + // Background Inner Shadow + CGRect backgroundBorderRect = CGRectInset([backgroundPath bounds], -innerShadowBlurRadius, -innerShadowBlurRadius); + backgroundBorderRect = CGRectOffset(backgroundBorderRect, -innerShadowOffset.width, -innerShadowOffset.height); + backgroundBorderRect = CGRectInset(CGRectUnion(backgroundBorderRect, [backgroundPath bounds]), -1, -1); + + UIBezierPath* backgroundNegativePath = [UIBezierPath bezierPathWithRect: backgroundBorderRect]; + [backgroundNegativePath appendPath: backgroundPath]; + backgroundNegativePath.usesEvenOddFillRule = YES; + + CGContextSaveGState(context); + { + CGFloat xOffset = innerShadowOffset.width + round(backgroundBorderRect.size.width); + CGFloat yOffset = innerShadowOffset.height; + CGContextSetShadowWithColor(context, + CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)), + innerShadowBlurRadius, + innerShadow.CGColor); + + [backgroundPath addClip]; + CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(backgroundBorderRect.size.width), 0); + [backgroundNegativePath applyTransform: transform]; + [[UIColor grayColor] setFill]; + [backgroundNegativePath fill]; + } + CGContextRestoreGState(context); + + CGContextRestoreGState(context); + + [strokeColor setStroke]; + backgroundPath.lineWidth = backgroundStrokeWidth; + [backgroundPath stroke]; + + + // Inner Stroke Drawing + CGFloat innerRadius = radius - 1.0; + CGRect anchorInnerRect = anchorRect; + anchorInnerRect.origin.x += backgroundStrokeWidth / 2; + anchorInnerRect.origin.y -= backgroundStrokeWidth / 2; + anchorInnerRect.size.width -= backgroundStrokeWidth; + anchorInnerRect.size.height -= backgroundStrokeWidth / 2; + + UIBezierPath* innerStrokePath = [UIBezierPath bezierPath]; + [innerStrokePath moveToPoint:CGPointMake(CGRectGetMinX(innerFrame), CGRectGetMinY(innerFrame) + innerRadius)]; + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(innerFrame), CGRectGetMaxY(innerFrame) - innerRadius)]; // left + [innerStrokePath addArcWithCenter:CGPointMake(CGRectGetMinX(innerFrame) + innerRadius, CGRectGetMaxY(innerFrame) - innerRadius) radius:innerRadius startAngle:M_PI endAngle:M_PI / 2 clockwise:NO]; // bottom-left corner + + // pointer down + if (!pointingUp) { + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorInnerRect), CGRectGetMaxY(innerFrame))]; + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorInnerRect) + anchorInnerRect.size.width / 2, CGRectGetMaxY(innerFrame) + anchorInnerRect.size.height)]; + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMaxX(anchorInnerRect), CGRectGetMaxY(innerFrame))]; + } + + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMaxX(innerFrame) - innerRadius, CGRectGetMaxY(innerFrame))]; // bottom + [innerStrokePath addArcWithCenter:CGPointMake(CGRectGetMaxX(innerFrame) - innerRadius, CGRectGetMaxY(innerFrame) - innerRadius) radius:innerRadius startAngle:M_PI / 2 endAngle:0.0f clockwise:NO]; // bottom-right corner + [innerStrokePath addLineToPoint: CGPointMake(CGRectGetMaxX(innerFrame), CGRectGetMinY(innerFrame) + innerRadius)]; // right + [innerStrokePath addArcWithCenter:CGPointMake(CGRectGetMaxX(innerFrame) - innerRadius, CGRectGetMinY(innerFrame) + innerRadius) radius:innerRadius startAngle:0.0f endAngle:-M_PI / 2 clockwise:NO]; // top-right corner + + // pointer up + if (pointingUp) { + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMaxX(anchorInnerRect), CGRectGetMinY(innerFrame))]; + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorInnerRect) + anchorRect.size.width / 2, CGRectGetMinY(innerFrame) - anchorInnerRect.size.height)]; + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorInnerRect), CGRectGetMinY(innerFrame))]; + } + + [innerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(innerFrame) + innerRadius, CGRectGetMinY(innerFrame))]; // top + [innerStrokePath addArcWithCenter:CGPointMake(CGRectGetMinX(innerFrame) + innerRadius, CGRectGetMinY(innerFrame) + innerRadius) radius:innerRadius startAngle:-M_PI / 2 endAngle:M_PI clockwise:NO]; // top-left corner + [innerStrokePath closePath]; + + [innerStrokeColor setStroke]; + innerStrokePath.lineWidth = backgroundStrokeWidth; + [innerStrokePath stroke]; + + + //// GlossGroup //// + { + CGContextSaveGState(context); + CGContextSetAlpha(context, 0.45); + CGContextBeginTransparencyLayer(context, NULL); + + CGFloat glossRadius = radius + 0.5; + + // Gloss Drawing + UIBezierPath* glossPath = [UIBezierPath bezierPath]; + [glossPath moveToPoint:CGPointMake(CGRectGetMinX(glossFrame), CGRectGetMinY(glossFrame))]; + [glossPath addLineToPoint:CGPointMake(CGRectGetMinX(glossFrame), CGRectGetMaxY(glossFrame) - glossRadius)]; // left + [glossPath addArcWithCenter:CGPointMake(CGRectGetMinX(glossFrame) + glossRadius, CGRectGetMaxY(glossFrame) - glossRadius) radius:glossRadius startAngle:M_PI endAngle:M_PI / 2 clockwise:NO]; // bottom-left corner + [glossPath addLineToPoint:CGPointMake(CGRectGetMaxX(glossFrame) - glossRadius, CGRectGetMaxY(glossFrame))]; // bottom + [glossPath addArcWithCenter:CGPointMake(CGRectGetMaxX(glossFrame) - glossRadius, CGRectGetMaxY(glossFrame) - glossRadius) radius:glossRadius startAngle:M_PI / 2 endAngle:0.0f clockwise:NO]; // bottom-right corner + [glossPath addLineToPoint: CGPointMake(CGRectGetMaxX(glossFrame), CGRectGetMinY(glossFrame) - glossRadius)]; // right + [glossPath addArcWithCenter:CGPointMake(CGRectGetMaxX(glossFrame) - glossRadius, CGRectGetMinY(glossFrame) + glossRadius) radius:glossRadius startAngle:0.0f endAngle:-M_PI / 2 clockwise:NO]; // top-right corner + + // pointer up + if (pointingUp) { + [glossPath addLineToPoint:CGPointMake(CGRectGetMaxX(anchorRect), CGRectGetMinY(glossFrame))]; + [glossPath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect) + roundf(anchorRect.size.width / 2), CGRectGetMinY(glossFrame) - anchorRect.size.height)]; + [glossPath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect), CGRectGetMinY(glossFrame))]; + } + + [glossPath addLineToPoint:CGPointMake(CGRectGetMinX(glossFrame) + glossRadius, CGRectGetMinY(glossFrame))]; // top + [glossPath addArcWithCenter:CGPointMake(CGRectGetMinX(glossFrame) + glossRadius, CGRectGetMinY(glossFrame) + glossRadius) radius:glossRadius startAngle:-M_PI / 2 endAngle:M_PI clockwise:NO]; // top-left corner + [glossPath closePath]; + + CGContextSaveGState(context); + [glossPath addClip]; + CGRect glossBounds = glossPath.bounds; + CGContextDrawLinearGradient(context, glossFill, + CGPointMake(CGRectGetMidX(glossBounds), CGRectGetMaxY(glossBounds)), + CGPointMake(CGRectGetMidX(glossBounds), CGRectGetMinY(glossBounds)), + 0); + CGContextRestoreGState(context); + + CGContextEndTransparencyLayer(context); + CGContextRestoreGState(context); + } + + CGContextEndTransparencyLayer(context); + CGContextRestoreGState(context); + } + + // Outer Stroke Drawing + UIBezierPath* outerStrokePath = [UIBezierPath bezierPath]; + [outerStrokePath moveToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMinY(frame) + radius)]; + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMaxY(frame) - radius)]; // left + [outerStrokePath addArcWithCenter:CGPointMake(CGRectGetMinX(frame) + radius, CGRectGetMaxY(frame) - radius) radius:radius startAngle:M_PI endAngle:M_PI / 2 clockwise:NO]; // bottom-left corner + + // pointer down + if (!pointingUp) { + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect), CGRectGetMaxY(frame))]; + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect) + anchorRect.size.width / 2, CGRectGetMaxY(frame) + anchorRect.size.height)]; + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMaxX(anchorRect), CGRectGetMaxY(frame))]; + } + + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMaxX(frame) - radius, CGRectGetMaxY(frame))]; // bottom + [outerStrokePath addArcWithCenter:CGPointMake(CGRectGetMaxX(frame) - radius, CGRectGetMaxY(frame) - radius) radius:radius startAngle:M_PI / 2 endAngle:0.0f clockwise:NO]; // bottom-right corner + [outerStrokePath addLineToPoint: CGPointMake(CGRectGetMaxX(frame), CGRectGetMinY(frame) + radius)]; // right + [outerStrokePath addArcWithCenter:CGPointMake(CGRectGetMaxX(frame) - radius, CGRectGetMinY(frame) + radius) radius:radius startAngle:0.0f endAngle:-M_PI / 2 clockwise:NO]; // top-right corner + + // pointer up + if (pointingUp) { + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMaxX(anchorRect), CGRectGetMinY(frame))]; + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect) + anchorRect.size.width / 2, CGRectGetMinY(frame) - anchorRect.size.height)]; + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(anchorRect), CGRectGetMinY(frame))]; + } + + [outerStrokePath addLineToPoint:CGPointMake(CGRectGetMinX(frame) + radius, CGRectGetMinY(frame))]; // top + [outerStrokePath addArcWithCenter:CGPointMake(CGRectGetMinX(frame) + radius, CGRectGetMinY(frame) + radius) radius:radius startAngle:-M_PI / 2 endAngle:M_PI clockwise:NO]; // top-left corner + [outerStrokePath closePath]; + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, baseShadowOffset, baseShadowBlurRadius, baseShadow.CGColor); + CGContextRestoreGState(context); + + [outerStrokeColor setStroke]; + outerStrokePath.lineWidth = outerStrokeStrokeWidth; + [outerStrokePath stroke]; + + //// Cleanup + CGGradientRelease(glossFill); + CGColorSpaceRelease(colorSpace); +} + +@end diff --git a/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.markdown b/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.markdown index e6afbb0..1573dac 100644 --- a/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.markdown +++ b/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.markdown @@ -239,6 +239,185 @@ THE SOFTWARE. +## SMCalloutView + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + ## SQLite.swift (The MIT License) diff --git a/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.plist b/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.plist index 89701ee..75927ab 100644 --- a/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.plist +++ b/Pods/Target Support Files/Pods-Delta/Pods-Delta-acknowledgements.plist @@ -274,6 +274,191 @@ THE SOFTWARE. Type PSGroupSpecifier + + FooterText + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + License + Apache License, Version 2.0 + Title + SMCalloutView + Type + PSGroupSpecifier + FooterText (The MIT License) diff --git a/Pods/Target Support Files/Pods-Delta/Pods-Delta-frameworks.sh b/Pods/Target Support Files/Pods-Delta/Pods-Delta-frameworks.sh index c984c6b..124ffbc 100755 --- a/Pods/Target Support Files/Pods-Delta/Pods-Delta-frameworks.sh +++ b/Pods/Target Support Files/Pods-Delta/Pods-Delta-frameworks.sh @@ -91,11 +91,13 @@ strip_invalid_archs() { if [[ "$CONFIGURATION" == "Debug" ]]; then install_framework "$BUILT_PRODUCTS_DIR/FileMD5Hash/FileMD5Hash.framework" install_framework "$BUILT_PRODUCTS_DIR/SDWebImage/SDWebImage.framework" + install_framework "$BUILT_PRODUCTS_DIR/SMCalloutView/SMCalloutView.framework" install_framework "$BUILT_PRODUCTS_DIR/SQLite.swift/SQLite.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_framework "$BUILT_PRODUCTS_DIR/FileMD5Hash/FileMD5Hash.framework" install_framework "$BUILT_PRODUCTS_DIR/SDWebImage/SDWebImage.framework" + install_framework "$BUILT_PRODUCTS_DIR/SMCalloutView/SMCalloutView.framework" install_framework "$BUILT_PRODUCTS_DIR/SQLite.swift/SQLite.framework" fi if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then diff --git a/Pods/Target Support Files/Pods-Delta/Pods-Delta.debug.xcconfig b/Pods/Target Support Files/Pods-Delta/Pods-Delta.debug.xcconfig index c077472..186d9d8 100644 --- a/Pods/Target Support Files/Pods-Delta/Pods-Delta.debug.xcconfig +++ b/Pods/Target Support Files/Pods-Delta/Pods-Delta.debug.xcconfig @@ -1,10 +1,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash" "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage" "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift" "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash" "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage" "$PODS_CONFIGURATION_BUILD_DIR/SMCalloutView" "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift" "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Crashlytics" "${PODS_ROOT}/Headers/Public/Fabric" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash/FileMD5Hash.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage/SDWebImage.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift/SQLite.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Crashlytics" -isystem "${PODS_ROOT}/Headers/Public/Fabric" -OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "Crashlytics" -framework "Fabric" -framework "FileMD5Hash" -framework "SDWebImage" -framework "SQLite" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash/FileMD5Hash.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage/SDWebImage.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SMCalloutView/SMCalloutView.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift/SQLite.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Crashlytics" -isystem "${PODS_ROOT}/Headers/Public/Fabric" +OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "Crashlytics" -framework "Fabric" -framework "FileMD5Hash" -framework "SDWebImage" -framework "SMCalloutView" -framework "SQLite" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Pods/Target Support Files/Pods-Delta/Pods-Delta.release.xcconfig b/Pods/Target Support Files/Pods-Delta/Pods-Delta.release.xcconfig index c077472..186d9d8 100644 --- a/Pods/Target Support Files/Pods-Delta/Pods-Delta.release.xcconfig +++ b/Pods/Target Support Files/Pods-Delta/Pods-Delta.release.xcconfig @@ -1,10 +1,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash" "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage" "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift" "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash" "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage" "$PODS_CONFIGURATION_BUILD_DIR/SMCalloutView" "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift" "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Crashlytics" "${PODS_ROOT}/Headers/Public/Fabric" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash/FileMD5Hash.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage/SDWebImage.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift/SQLite.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Crashlytics" -isystem "${PODS_ROOT}/Headers/Public/Fabric" -OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "Crashlytics" -framework "Fabric" -framework "FileMD5Hash" -framework "SDWebImage" -framework "SQLite" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FileMD5Hash/FileMD5Hash.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage/SDWebImage.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SMCalloutView/SMCalloutView.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/SQLite.swift/SQLite.framework/Headers" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/Crashlytics" -isystem "${PODS_ROOT}/Headers/Public/Fabric" +OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"z" -framework "Crashlytics" -framework "Fabric" -framework "FileMD5Hash" -framework "SDWebImage" -framework "SMCalloutView" -framework "SQLite" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Pods/Target Support Files/SMCalloutView/Info.plist b/Pods/Target Support Files/SMCalloutView/Info.plist new file mode 100644 index 0000000..a73567e --- /dev/null +++ b/Pods/Target Support Files/SMCalloutView/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.1.5 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/SMCalloutView/SMCalloutView-dummy.m b/Pods/Target Support Files/SMCalloutView/SMCalloutView-dummy.m new file mode 100644 index 0000000..f570a18 --- /dev/null +++ b/Pods/Target Support Files/SMCalloutView/SMCalloutView-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_SMCalloutView : NSObject +@end +@implementation PodsDummy_SMCalloutView +@end diff --git a/Pods/Target Support Files/SMCalloutView/SMCalloutView-prefix.pch b/Pods/Target Support Files/SMCalloutView/SMCalloutView-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/SMCalloutView/SMCalloutView-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/SMCalloutView/SMCalloutView-umbrella.h b/Pods/Target Support Files/SMCalloutView/SMCalloutView-umbrella.h new file mode 100644 index 0000000..01c9303 --- /dev/null +++ b/Pods/Target Support Files/SMCalloutView/SMCalloutView-umbrella.h @@ -0,0 +1,18 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "SMCalloutView.h" +#import "SMClassicCalloutView.h" + +FOUNDATION_EXPORT double SMCalloutViewVersionNumber; +FOUNDATION_EXPORT const unsigned char SMCalloutViewVersionString[]; + diff --git a/Pods/Target Support Files/SMCalloutView/SMCalloutView.modulemap b/Pods/Target Support Files/SMCalloutView/SMCalloutView.modulemap new file mode 100644 index 0000000..72f1d32 --- /dev/null +++ b/Pods/Target Support Files/SMCalloutView/SMCalloutView.modulemap @@ -0,0 +1,6 @@ +framework module SMCalloutView { + umbrella header "SMCalloutView-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/SMCalloutView/SMCalloutView.xcconfig b/Pods/Target Support Files/SMCalloutView/SMCalloutView.xcconfig new file mode 100644 index 0000000..7164995 --- /dev/null +++ b/Pods/Target Support Files/SMCalloutView/SMCalloutView.xcconfig @@ -0,0 +1,9 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/SMCalloutView +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Crashlytics" "${PODS_ROOT}/Headers/Public/Fabric" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/SMCalloutView +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES