diff --git a/LNPCSwiftRefinements/SwiftRefinements.swift b/LNPCSwiftRefinements/SwiftRefinements.swift index b6f343d..7c071ef 100644 --- a/LNPCSwiftRefinements/SwiftRefinements.swift +++ b/LNPCSwiftRefinements/SwiftRefinements.swift @@ -2,8 +2,8 @@ // SwiftRefinements.swift // LNPopupController // -// Created by Leo Natan on 8/2/21. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-08-02. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // import UIKit @@ -11,6 +11,48 @@ import UIKit @_exported import LNPopupController_ObjC #endif +#if canImport(SwiftUI) +import SwiftUI + +@available(iOS 13, *) +@_cdecl("__ln_doNotCall__fixUIHostingViewHitTest") +@_spi(LNPopupControllerInternal) +public +func __ln_doNotCall__fixUIHostingViewHitTest() { + DispatchQueue.main.async { + guard let view = UIHostingController(rootView: EmptyView()).view else { + return + } + + let cls = type(of: view) + let sel = #selector(UIView.hitTest(_:with:)) + let method = class_getInstanceMethod(cls, sel)! + + let _orig: @convention(c) (_ self: UIView, _ sel: Selector, _ point: CGPoint, _ event: UIEvent?) -> UIView? + _orig = unsafeBitCast(method_getImplementation(method), to: type(of: _orig)) + + let orig: (UIView, CGPoint, UIEvent?) -> UIView? = { _self, point, event in + _orig(_self, sel, point, event) + } + + let impl: @convention(block) (UIView, CGPoint, UIEvent?) -> UIView? = { _self, point, event in + if let popupContentView = _self.subviews.filter({ $0 is LNPopupContentView }).first, popupContentView.point(inside: popupContentView.convert(point, from: _self), with: event), let popupContentViewHitTest = popupContentView.hitTest(popupContentView.convert(point, from: _self), with: event) { + return popupContentViewHitTest + } + + if let popupBar = _self.subviews.filter({ $0 is LNPopupBar }).first, popupBar.point(inside: popupBar.convert(point, from: _self), with: event), let popupBarHitTest = popupBar.hitTest(popupBar.convert(point, from: _self), with: event) { + return popupBarHitTest + } + + return orig(_self, point, event) + } + + method_setImplementation(method, imp_implementationWithBlock(impl)) + } +} +#endif + +public extension Double { /// The default popup snap percent. See `LNPopupInteractionStyle.customizedSnap(percent:)` for more information. static var defaultPopupSnapPercent: Double { @@ -18,7 +60,8 @@ extension Double { } } -public extension UIViewController { +public +extension UIViewController { /// Available interaction styles with the popup bar and popup content view. enum PopupInteractionStyle { /// The default interaction style for the current environment. @@ -35,26 +78,30 @@ public extension UIViewController { /// No interaction. case none } - + /// The popup bar interaction style. var popupInteractionStyle: PopupInteractionStyle { get { switch __popupInteractionStyle { - case .none: - return .none + case .default: + return .default case .drag: return .drag case .snap: return __popupSnapPercent == .defaultPopupSnapPercent ? .snap : .customizedSnap(percent: __popupSnapPercent) - default: - return .default + case .scroll: + return .scroll + case .none: + return .none + @unknown default: + fatalError("Please open an issue here: https://github.com/LeoNatan/LNPopupController/issues/new/choose") } } set { switch newValue { - case .none: - __popupInteractionStyle = .none + case .default: + __popupInteractionStyle = .default return case .drag: __popupInteractionStyle = .drag @@ -67,15 +114,36 @@ public extension UIViewController { __popupInteractionStyle = .snap __popupSnapPercent = percent return - default: - __popupInteractionStyle = .default + case .scroll: + __popupInteractionStyle = .scroll + return + case .none: + __popupInteractionStyle = .none return } } } + + var effectivePopupInteractionStyle: PopupInteractionStyle { + switch __effectivePopupInteractionStyle { + case .drag: + return .drag + case .snap: + return __popupSnapPercent == .defaultPopupSnapPercent ? .snap : .customizedSnap(percent: __popupSnapPercent) + case .scroll: + return .scroll + case .none: + return .none + case .default: + fallthrough + @unknown default: + fatalError("Please open an issue here: https://github.com/LeoNatan/LNPopupController/issues/new/choose") + } + } } -public extension LNPopupItem { +public +extension LNPopupItem { /// The popup item's attributed title. /// /// If no title or subtitle is set, the system will use the view controller's title. @@ -101,8 +169,9 @@ public extension LNPopupItem { } } -@available(iOS 13.0, *) -public extension LNPopupBarAppearance { +@available(iOS 13, *) +public +extension LNPopupBarAppearance { /// Display attributes for the popup bar’s title text. /// /// Only attributes from the UIKit scope are supported. @@ -129,3 +198,59 @@ public extension LNPopupBarAppearance { } } } + +public +extension UIViewController { + /// Presents an interactive popup bar in the receiver's view hierarchy and optionally opens the popup in the same animation. The popup bar is attached to the receiver's docking view. + /// + /// You may call this method multiple times with different controllers, triggering replacement to the popup content view and update to the popup bar, if popup is open or bar presented, respectively. + /// + /// The provided controller is retained by the system and will be released once a different controller is presented or when the popup bar is dismissed. + /// - Parameters: + /// - contentViewController: The controller for popup presentation. + /// - openPopup: Pass `true` to open the popup in the same animation; otherwise, pass `false`. + /// - animated: Pass `true` to animate the presentation; otherwise, pass `false`. + /// - completion: The block to execute after the presentation finishes. This block has no return value and takes no parameters. You may specify `nil` for this parameter. + func presentPopupBar(with contentViewController: UIViewController, openPopup: Bool = false, animated: Bool, completion: (() -> Void)? = nil) { + __presentPopupBar(withContentViewController: contentViewController, openPopup: openPopup, animated: animated, completion: completion) + } + + /// Presents an interactive popup bar in the receiver's view hierarchy and optionally opens the popup in the same animation. The popup bar is attached to the receiver's docking view. + /// + /// You may call this method multiple times with different controllers, triggering replacement to the popup content view and update to the popup bar, if popup is open or bar presented, respectively. + /// + /// The provided controller is retained by the system and will be released once a different controller is presented or when the popup bar is dismissed. + /// - Parameters: + /// - contentViewController: The controller for popup presentation. + /// - openPopup: Pass `true` to open the popup in the same animation; otherwise, pass `false`. + /// - animated: Pass `true` to animate the presentation; otherwise, pass `false`. + /// - completion: The block to execute after the presentation finishes. This block has no return value and takes no parameters. You may specify `nil` for this parameter. + @available(*, deprecated, message: "Use presentPopupBar(with:openPopup:animated:completion:) instead.") + func presentPopupBar(withContentViewController contentViewController: UIViewController, openPopup: Bool = false, animated: Bool, completion: (() -> Void)? = nil) { + __presentPopupBar(withContentViewController: contentViewController, openPopup: openPopup, animated: animated, completion: completion) + } + + /// Opens the popup, displaying the content view controller's view. + /// - Parameters: + /// - animated: Pass `true` to animate; otherwise, pass `false`. + /// - completion: The block to execute after the popup is opened. This block has no return value and takes no parameters. You may specify `nil` for this parameter. + func openPopup(animated: Bool, completion: (() -> Void)? = nil) { + __openPopup(animated: animated, completion: completion) + } + + /// Closes the popup, hiding the content view controller's view. + /// - Parameters: + /// - animated: Pass `true` to animate; otherwise, pass `false`. + /// - completion: The block to execute after the popup is closed. This block has no return value and takes no parameters. You may specify `nil` for this parameter. + func closePopup(animated: Bool, completion: (() -> Void)? = nil) { + __closePopup(animated: animated, completion: completion) + } + + /// Dismisses the popup presentation, closing the popup if open and dismissing the popup bar. + /// - Parameters: + /// - animated: Pass `true` to animate; otherwise, pass `false`. + /// - completion: The block to execute after the dismissal. This block has no return value and takes no parameters. You may specify `nil` for this parameter. + func dismissPopupBar(animated: Bool, completion: (() -> Void)? = nil) { + __dismissPopupBar(animated: animated, completion: completion) + } +} diff --git a/LNPopupController/Info.plist b/LNPopupController/Info.plist index 3222b32..944c736 100644 --- a/LNPopupController/Info.plist +++ b/LNPopupController/Info.plist @@ -9,7 +9,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.18.2 + 3.0.6 CFBundleVersion 1 LSRequiresIPhoneOS diff --git a/LNPopupController/LNPopupController.h b/LNPopupController/LNPopupController.h index 71d40be..41a1cee 100644 --- a/LNPopupController/LNPopupController.h +++ b/LNPopupController/LNPopupController.h @@ -2,8 +2,8 @@ // LNPopupController.h // LNPopupController // -// Created by Leo Natan on 7/17/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController.xcodeproj/project.pbxproj b/LNPopupController/LNPopupController.xcodeproj/project.pbxproj index 1ef2dd1..b64a61b 100644 --- a/LNPopupController/LNPopupController.xcodeproj/project.pbxproj +++ b/LNPopupController/LNPopupController.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -13,37 +13,37 @@ 390DD0111BB2EAC30064DB4A /* LNPopupContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 390DD0101BB2EAC30064DB4A /* LNPopupContentView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 391481BA1DCFA514002416D1 /* LNChevronView.m in Sources */ = {isa = PBXBuildFile; fileRef = 391481B81DCFA514002416D1 /* LNChevronView.m */; }; 391481BB1DCFA514002416D1 /* LNChevronView.h in Headers */ = {isa = PBXBuildFile; fileRef = 391481B91DCFA514002416D1 /* LNChevronView.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 392200702C663A03008AFD36 /* _LNPopupAddressInfo.h in Sources */ = {isa = PBXBuildFile; fileRef = 3922006F2C663A03008AFD36 /* _LNPopupAddressInfo.h */; }; 39222ADB1F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 39222AD91F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 39222ADC1F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 39222ADA1F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.m */; }; 39314A521B6AE7A400574D3C /* MarqueeLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = 39314A501B6AE7A400574D3C /* MarqueeLabel.h */; settings = {ATTRIBUTES = (Private, ); }; }; 39314A531B6AE7A400574D3C /* MarqueeLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 39314A511B6AE7A400574D3C /* MarqueeLabel.m */; }; - 393E4EA72670F12500929E47 /* LNPopupBarAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 393E4EA52670F12500929E47 /* LNPopupBarAppearance.m */; }; + 393E4EA72670F12500929E47 /* LNPopupBarAppearance.mm in Sources */ = {isa = PBXBuildFile; fileRef = 393E4EA52670F12500929E47 /* LNPopupBarAppearance.mm */; }; 393E4EAA2670F2D000929E47 /* LNPopupBarAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 393E4EA82670F2D000929E47 /* LNPopupBarAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; }; 394005FC2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.h in Headers */ = {isa = PBXBuildFile; fileRef = 394005FA2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.h */; }; 394005FD2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.m in Sources */ = {isa = PBXBuildFile; fileRef = 394005FB2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.m */; }; 3947E1A11B61CD1F0001178B /* UIViewController+LNPopupSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 3947E19F1B61CD1F0001178B /* UIViewController+LNPopupSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3947E1A21B61CD1F0001178B /* UIViewController+LNPopupSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1A01B61CD1F0001178B /* UIViewController+LNPopupSupport.m */; }; - 3947E1A61B61CD650001178B /* LNPopupBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1A41B61CD650001178B /* LNPopupBar.m */; }; + 3947E1A21B61CD1F0001178B /* UIViewController+LNPopupSupport.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1A01B61CD1F0001178B /* UIViewController+LNPopupSupport.mm */; }; + 3947E1A61B61CD650001178B /* LNPopupBar.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1A41B61CD650001178B /* LNPopupBar.mm */; }; 3947E1A91B61CDA40001178B /* LNPopupCloseButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 3947E1A71B61CDA40001178B /* LNPopupCloseButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3947E1AA1B61CDA40001178B /* LNPopupCloseButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1A81B61CDA40001178B /* LNPopupCloseButton.m */; }; + 3947E1AA1B61CDA40001178B /* LNPopupCloseButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1A81B61CDA40001178B /* LNPopupCloseButton.mm */; }; 3947E1B21B61CE4A0001178B /* LNPopupController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3947E1B01B61CE4A0001178B /* LNPopupController.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 3947E1B31B61CE4A0001178B /* LNPopupController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1B11B61CE4A0001178B /* LNPopupController.m */; }; + 3947E1B31B61CE4A0001178B /* LNPopupController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3947E1B11B61CE4A0001178B /* LNPopupController.mm */; }; 3947E1BA1B6300370001178B /* LNPopupBar+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3947E1B81B6300370001178B /* LNPopupBar+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 394A85B61B630409004FFC61 /* LNPopupBar.h in Headers */ = {isa = PBXBuildFile; fileRef = 394A85B51B630409004FFC61 /* LNPopupBar.h */; settings = {ATTRIBUTES = (Public, ); }; }; 394A85BA1B6304F5004FFC61 /* LNPopupItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 394A85B81B6304F5004FFC61 /* LNPopupItem.m */; }; 394A85BD1B6306AE004FFC61 /* LNPopupItem+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 394A85BB1B6306AE004FFC61 /* LNPopupItem+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 394A85C11B630992004FFC61 /* _LNWeakRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 394A85BF1B630992004FFC61 /* _LNWeakRef.h */; }; 394A85C21B630992004FFC61 /* _LNWeakRef.m in Sources */ = {isa = PBXBuildFile; fileRef = 394A85C01B630992004FFC61 /* _LNWeakRef.m */; }; - 394A85C91B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 394A85C81B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.m */; }; - 39500DFF2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 39500DFD2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.h */; }; - 39500E002B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 39500DFE2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.m */; }; + 394A85C91B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 394A85C81B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.mm */; }; 39599BAA1E02CD65008EE386 /* LNPopupCustomBarViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 39599BA81E02CD65008EE386 /* LNPopupCustomBarViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 39599BAB1E02CD65008EE386 /* LNPopupCustomBarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39599BA91E02CD65008EE386 /* LNPopupCustomBarViewController.m */; }; 39599BAD1E02CDF4008EE386 /* LNPopupCustomBarViewController+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 39599BAC1E02CDF4008EE386 /* LNPopupCustomBarViewController+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 396A8DE826BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 396A8DE626BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.h */; }; 396A8DE926BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 396A8DE726BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.m */; }; 396D62722610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 396D62702610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.h */; }; - 396D62732610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 396D62712610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.m */; }; + 396D62732610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 396D62712610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.mm */; }; + 3975A5C42C663B520027FCDD /* _LNPopupAddressInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 392200712C663A23008AFD36 /* _LNPopupAddressInfo.mm */; }; 397AFBFB1F1A1ED200E7D95C /* LNForwardingDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 397AFBF91F1A1ED200E7D95C /* LNForwardingDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 397AFBFC1F1A1ED200E7D95C /* LNForwardingDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 397AFBFA1F1A1ED200E7D95C /* LNForwardingDelegate.m */; }; 397AFC011F1A21DD00E7D95C /* LNPopupLongPressGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 397AFBFF1F1A21DD00E7D95C /* LNPopupLongPressGestureRecognizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -56,21 +56,43 @@ 398C2902260CCDA6000690FB /* LNPopupCloseButton+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 39109DA11DD8A305004B5FAB /* LNPopupCloseButton+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 398C2903260CCDA6000690FB /* LNPopupContentView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3907CDB924D9BD8A007C9300 /* LNPopupContentView+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 399BA1D42A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 399BA1D22A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.h */; }; - 399BA1D52A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 399BA1D32A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.m */; }; - 399D37B82ADC672D00EA5038 /* _LNPopupBarShadowedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 399D37B62ADC672D00EA5038 /* _LNPopupBarShadowedImageView.h */; }; - 399D37B92ADC672D00EA5038 /* _LNPopupBarShadowedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 399D37B72ADC672D00EA5038 /* _LNPopupBarShadowedImageView.m */; }; + 399BA1D52A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.mm in Sources */ = {isa = PBXBuildFile; fileRef = 399BA1D32A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.mm */; }; + 399D37B82ADC672D00EA5038 /* LNPopupImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 399D37B62ADC672D00EA5038 /* LNPopupImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 399D37B92ADC672D00EA5038 /* LNPopupImageView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 399D37B72ADC672D00EA5038 /* LNPopupImageView.mm */; }; 39A0DDB326F7894700E5D751 /* NSAttributedString+LNPopupSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 39A0DDB126F7894700E5D751 /* NSAttributedString+LNPopupSupport.h */; }; 39A0DDB426F7894700E5D751 /* NSAttributedString+LNPopupSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 39A0DDB226F7894700E5D751 /* NSAttributedString+LNPopupSupport.m */; }; 39A9249A1B58530A003C1C19 /* LNPopupController.h in Headers */ = {isa = PBXBuildFile; fileRef = 39A924991B5852ED003C1C19 /* LNPopupController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 39AC479126C69ACA001D53C2 /* LNMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 39AC478F26C69AC9001D53C2 /* LNMath.h */; }; 39AC479226C69ACA001D53C2 /* LNMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 39AC479026C69AC9001D53C2 /* LNMath.m */; }; + 39AF84EE2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 39AF84ED2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.m */; }; + 39AF84EF2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 39AF84EC2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.h */; }; 39B3EB0D24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B3EB0B24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 39B3EB0E24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 39B3EB0C24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.m */; }; + 39B3EB0E24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39B3EB0C24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.mm */; }; + 39B5500D2D92D29000B474EC /* _LNPopupTransitionAnimator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39B550002D92D29000B474EC /* _LNPopupTransitionAnimator.mm */; }; + 39B5500E2D92D29000B474EC /* _LNPopupTransitionCloseAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 39B550022D92D29000B474EC /* _LNPopupTransitionCloseAnimator.m */; }; + 39B5500F2D92D29000B474EC /* _LNPopupTransitionOpenAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 39B550082D92D29000B474EC /* _LNPopupTransitionOpenAnimator.m */; }; + 39B550102D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39B5500C2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.mm */; }; + 39B550112D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39B5500A2D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.mm */; }; + 39B550122D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 39B550062D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.m */; }; + 39B550132D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 39B550042D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.m */; }; + 39B550142D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B5500B2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.h */; }; + 39B550152D92D29000B474EC /* _LNPopupTransitionOpenAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550072D92D29000B474EC /* _LNPopupTransitionOpenAnimator.h */; }; + 39B550162D92D29000B474EC /* _LNPopupTransitionCloseAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550012D92D29000B474EC /* _LNPopupTransitionCloseAnimator.h */; }; + 39B550172D92D29000B474EC /* _LNPopupTransitionAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B54FFF2D92D29000B474EC /* _LNPopupTransitionAnimator.h */; }; + 39B550182D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550032D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.h */; }; + 39B550192D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550092D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.h */; }; + 39B5501A2D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.h in Headers */ = {isa = PBXBuildFile; fileRef = 39B550052D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.h */; }; + 39C553DF2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39C553DE2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm */; }; + 39C553E02D8F2B3200F8D8B2 /* _LNPopupTransitionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 39C553DD2D8F2B3200F8D8B2 /* _LNPopupTransitionView.h */; }; + 39C553E32D91925300F8D8B2 /* LNPopupImageView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 39C553E22D91924900F8D8B2 /* LNPopupImageView+Private.h */; }; 39C81A321B642DDD00D3B645 /* LNPopupItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 394A85B71B6304F5004FFC61 /* LNPopupItem.h */; settings = {ATTRIBUTES = (Public, ); }; }; 39E7A604200B5157007AF3AD /* _LNPopupSwizzlingUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 39E7A602200B5157007AF3AD /* _LNPopupSwizzlingUtils.h */; }; 39E7A605200B5157007AF3AD /* _LNPopupSwizzlingUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 39E7A603200B5157007AF3AD /* _LNPopupSwizzlingUtils.m */; }; 39E9FE11275B984B00A47D61 /* LNPopupDefinitions.h in Headers */ = {isa = PBXBuildFile; fileRef = 39E9FE10275B97CC00A47D61 /* LNPopupDefinitions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 39F8228826B80B6F0070DDBA /* SwiftRefinements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F8228726B80B6F0070DDBA /* SwiftRefinements.swift */; }; + 39F9DECA2C84A211005CA5FB /* _LNPopupBase64Utils.hh in Headers */ = {isa = PBXBuildFile; fileRef = 39F9DEC92C84A207005CA5FB /* _LNPopupBase64Utils.hh */; }; + 39FA8FD12D9F84000068FD0D /* LNPopupDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 39FA8FCF2D9F84000068FD0D /* LNPopupDebug.h */; }; + 39FA8FD22D9F84000068FD0D /* LNPopupDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 39FA8FD02D9F84000068FD0D /* LNPopupDebug.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -82,22 +104,24 @@ 39109DA11DD8A305004B5FAB /* LNPopupCloseButton+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LNPopupCloseButton+Private.h"; sourceTree = ""; }; 391481B81DCFA514002416D1 /* LNChevronView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNChevronView.m; sourceTree = ""; }; 391481B91DCFA514002416D1 /* LNChevronView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNChevronView.h; sourceTree = ""; }; + 3922006F2C663A03008AFD36 /* _LNPopupAddressInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupAddressInfo.h; sourceTree = ""; }; + 392200712C663A23008AFD36 /* _LNPopupAddressInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupAddressInfo.mm; sourceTree = ""; }; 39222AD91F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupOpenTapGestureRecognizer.h; sourceTree = ""; }; 39222ADA1F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LNPopupOpenTapGestureRecognizer.m; sourceTree = ""; }; 39314A501B6AE7A400574D3C /* MarqueeLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarqueeLabel.h; sourceTree = ""; }; 39314A511B6AE7A400574D3C /* MarqueeLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarqueeLabel.m; sourceTree = ""; }; - 393E4EA52670F12500929E47 /* LNPopupBarAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LNPopupBarAppearance.m; sourceTree = ""; }; + 393E4EA52670F12500929E47 /* LNPopupBarAppearance.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LNPopupBarAppearance.mm; sourceTree = ""; }; 393E4EA82670F2D000929E47 /* LNPopupBarAppearance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupBarAppearance.h; sourceTree = ""; }; 393E4EAC26713E5700929E47 /* LNPopupBarAppearance+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LNPopupBarAppearance+Private.h"; sourceTree = ""; }; 394005FA2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupBarBackgroundMaskView.h; sourceTree = ""; }; 394005FB2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupBarBackgroundMaskView.m; sourceTree = ""; }; 3947E19F1B61CD1F0001178B /* UIViewController+LNPopupSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "UIViewController+LNPopupSupport.h"; sourceTree = ""; }; - 3947E1A01B61CD1F0001178B /* UIViewController+LNPopupSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "UIViewController+LNPopupSupport.m"; sourceTree = ""; }; - 3947E1A41B61CD650001178B /* LNPopupBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNPopupBar.m; sourceTree = ""; }; + 3947E1A01B61CD1F0001178B /* UIViewController+LNPopupSupport.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "UIViewController+LNPopupSupport.mm"; sourceTree = ""; }; + 3947E1A41B61CD650001178B /* LNPopupBar.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LNPopupBar.mm; sourceTree = ""; }; 3947E1A71B61CDA40001178B /* LNPopupCloseButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopupCloseButton.h; sourceTree = ""; }; - 3947E1A81B61CDA40001178B /* LNPopupCloseButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNPopupCloseButton.m; sourceTree = ""; }; + 3947E1A81B61CDA40001178B /* LNPopupCloseButton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LNPopupCloseButton.mm; sourceTree = ""; }; 3947E1B01B61CE4A0001178B /* LNPopupController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopupController.h; sourceTree = ""; }; - 3947E1B11B61CE4A0001178B /* LNPopupController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = LNPopupController.m; sourceTree = ""; }; + 3947E1B11B61CE4A0001178B /* LNPopupController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = LNPopupController.mm; sourceTree = ""; }; 3947E1B81B6300370001178B /* LNPopupBar+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "LNPopupBar+Private.h"; sourceTree = ""; }; 394A85B51B630409004FFC61 /* LNPopupBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopupBar.h; sourceTree = ""; }; 394A85B71B6304F5004FFC61 /* LNPopupItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopupItem.h; sourceTree = ""; }; @@ -106,16 +130,14 @@ 394A85BF1B630992004FFC61 /* _LNWeakRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _LNWeakRef.h; sourceTree = ""; }; 394A85C01B630992004FFC61 /* _LNWeakRef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _LNWeakRef.m; sourceTree = ""; }; 394A85C71B63FB96004FFC61 /* UIViewController+LNPopupSupportPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+LNPopupSupportPrivate.h"; sourceTree = ""; }; - 394A85C81B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "UIViewController+LNPopupSupportPrivate.m"; sourceTree = ""; }; - 39500DFD2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupBarAppearanceLegacySupport.h; sourceTree = ""; }; - 39500DFE2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupBarAppearanceLegacySupport.m; sourceTree = ""; }; + 394A85C81B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "UIViewController+LNPopupSupportPrivate.mm"; sourceTree = ""; }; 39599BA81E02CD65008EE386 /* LNPopupCustomBarViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopupCustomBarViewController.h; sourceTree = ""; }; 39599BA91E02CD65008EE386 /* LNPopupCustomBarViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNPopupCustomBarViewController.m; sourceTree = ""; }; 39599BAC1E02CDF4008EE386 /* LNPopupCustomBarViewController+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "LNPopupCustomBarViewController+Private.h"; sourceTree = ""; }; 396A8DE626BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupBarAppearanceChainProxy.h; sourceTree = ""; }; 396A8DE726BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LNPopupBarAppearanceChainProxy.m; sourceTree = ""; }; 396D62702610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIContextMenuInteraction+LNPopupSupportPrivate.h"; sourceTree = ""; }; - 396D62712610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIContextMenuInteraction+LNPopupSupportPrivate.m"; sourceTree = ""; }; + 396D62712610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIContextMenuInteraction+LNPopupSupportPrivate.mm"; sourceTree = ""; }; 397AFBF91F1A1ED200E7D95C /* LNForwardingDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNForwardingDelegate.h; sourceTree = ""; }; 397AFBFA1F1A1ED200E7D95C /* LNForwardingDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNForwardingDelegate.m; sourceTree = ""; }; 397AFBFF1F1A21DD00E7D95C /* LNPopupLongPressGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupLongPressGestureRecognizer.h; sourceTree = ""; }; @@ -125,21 +147,43 @@ 397D9A152687474D005164AB /* _LNPopupBarBackgroundView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupBarBackgroundView.h; sourceTree = ""; }; 397D9A162687474D005164AB /* _LNPopupBarBackgroundView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupBarBackgroundView.m; sourceTree = ""; }; 399BA1D22A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupUIBarAppearanceProxy.h; sourceTree = ""; }; - 399BA1D32A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupUIBarAppearanceProxy.m; sourceTree = ""; }; - 399D37B62ADC672D00EA5038 /* _LNPopupBarShadowedImageView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupBarShadowedImageView.h; sourceTree = ""; }; - 399D37B72ADC672D00EA5038 /* _LNPopupBarShadowedImageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupBarShadowedImageView.m; sourceTree = ""; }; + 399BA1D32A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupUIBarAppearanceProxy.mm; sourceTree = ""; }; + 399D37B62ADC672D00EA5038 /* LNPopupImageView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupImageView.h; sourceTree = ""; }; + 399D37B72ADC672D00EA5038 /* LNPopupImageView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LNPopupImageView.mm; sourceTree = ""; }; 39A0DDB126F7894700E5D751 /* NSAttributedString+LNPopupSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+LNPopupSupport.h"; sourceTree = ""; }; 39A0DDB226F7894700E5D751 /* NSAttributedString+LNPopupSupport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+LNPopupSupport.m"; sourceTree = ""; }; 39A924991B5852ED003C1C19 /* LNPopupController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupController.h; sourceTree = ""; }; 39AC478F26C69AC9001D53C2 /* LNMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNMath.h; sourceTree = ""; }; 39AC479026C69AC9001D53C2 /* LNMath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNMath.m; sourceTree = ""; }; + 39AF84EC2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupBarAppearanceLegacySupport.h; sourceTree = ""; }; + 39AF84ED2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupBarAppearanceLegacySupport.m; sourceTree = ""; }; 39B3EB0B24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+LNPopupSupportPrivate.h"; sourceTree = ""; }; - 39B3EB0C24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+LNPopupSupportPrivate.m"; sourceTree = ""; }; + 39B3EB0C24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIView+LNPopupSupportPrivate.mm"; sourceTree = ""; }; + 39B54FFF2D92D29000B474EC /* _LNPopupTransitionAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionAnimator.h; sourceTree = ""; }; + 39B550002D92D29000B474EC /* _LNPopupTransitionAnimator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupTransitionAnimator.mm; sourceTree = ""; }; + 39B550012D92D29000B474EC /* _LNPopupTransitionCloseAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionCloseAnimator.h; sourceTree = ""; }; + 39B550022D92D29000B474EC /* _LNPopupTransitionCloseAnimator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupTransitionCloseAnimator.m; sourceTree = ""; }; + 39B550032D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionGenericCloseAnimator.h; sourceTree = ""; }; + 39B550042D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupTransitionGenericCloseAnimator.m; sourceTree = ""; }; + 39B550052D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionGenericOpenAnimator.h; sourceTree = ""; }; + 39B550062D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupTransitionGenericOpenAnimator.m; sourceTree = ""; }; + 39B550072D92D29000B474EC /* _LNPopupTransitionOpenAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionOpenAnimator.h; sourceTree = ""; }; + 39B550082D92D29000B474EC /* _LNPopupTransitionOpenAnimator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupTransitionOpenAnimator.m; sourceTree = ""; }; + 39B550092D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionPreferredCloseAnimator.h; sourceTree = ""; }; + 39B5500A2D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupTransitionPreferredCloseAnimator.mm; sourceTree = ""; }; + 39B5500B2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionPreferredOpenAnimator.h; sourceTree = ""; }; + 39B5500C2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupTransitionPreferredOpenAnimator.mm; sourceTree = ""; }; + 39C553DD2D8F2B3200F8D8B2 /* _LNPopupTransitionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupTransitionView.h; sourceTree = ""; }; + 39C553DE2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _LNPopupTransitionView.mm; sourceTree = ""; }; + 39C553E22D91924900F8D8B2 /* LNPopupImageView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LNPopupImageView+Private.h"; sourceTree = ""; }; 39DB52E51B5823330061C589 /* LNPopupController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LNPopupController.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 39E7A602200B5157007AF3AD /* _LNPopupSwizzlingUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _LNPopupSwizzlingUtils.h; sourceTree = ""; }; 39E7A603200B5157007AF3AD /* _LNPopupSwizzlingUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _LNPopupSwizzlingUtils.m; sourceTree = ""; }; 39E9FE10275B97CC00A47D61 /* LNPopupDefinitions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupDefinitions.h; sourceTree = ""; }; 39F8228726B80B6F0070DDBA /* SwiftRefinements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SwiftRefinements.swift; path = ../../LNPCSwiftRefinements/SwiftRefinements.swift; sourceTree = ""; }; + 39F9DEC92C84A207005CA5FB /* _LNPopupBase64Utils.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = _LNPopupBase64Utils.hh; sourceTree = ""; }; + 39FA8FCF2D9F84000068FD0D /* LNPopupDebug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupDebug.h; sourceTree = ""; }; + 39FA8FD02D9F84000068FD0D /* LNPopupDebug.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LNPopupDebug.m; sourceTree = ""; }; 46ECC2AE1BF31025005CE96C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -157,6 +201,7 @@ 3947E1AB1B61CDD70001178B /* Implementation */ = { isa = PBXGroup; children = ( + 39F9DEC92C84A207005CA5FB /* _LNPopupBase64Utils.hh */, 39E7A602200B5157007AF3AD /* _LNPopupSwizzlingUtils.h */, 39E7A603200B5157007AF3AD /* _LNPopupSwizzlingUtils.m */, 394A85BF1B630992004FFC61 /* _LNWeakRef.h */, @@ -170,22 +215,25 @@ 397D9A162687474D005164AB /* _LNPopupBarBackgroundView.m */, 394005FA2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.h */, 394005FB2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.m */, - 399D37B62ADC672D00EA5038 /* _LNPopupBarShadowedImageView.h */, - 399D37B72ADC672D00EA5038 /* _LNPopupBarShadowedImageView.m */, + 39C553E22D91924900F8D8B2 /* LNPopupImageView+Private.h */, + 399D37B72ADC672D00EA5038 /* LNPopupImageView.mm */, + 39C553DD2D8F2B3200F8D8B2 /* _LNPopupTransitionView.h */, + 39C553DE2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm */, 3947E1B81B6300370001178B /* LNPopupBar+Private.h */, - 3947E1A41B61CD650001178B /* LNPopupBar.m */, + 3947E1A41B61CD650001178B /* LNPopupBar.mm */, 393E4EAC26713E5700929E47 /* LNPopupBarAppearance+Private.h */, - 393E4EA52670F12500929E47 /* LNPopupBarAppearance.m */, + 393E4EA52670F12500929E47 /* LNPopupBarAppearance.mm */, 396A8DE626BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.h */, 396A8DE726BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.m */, - 39500DFD2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.h */, - 39500DFE2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.m */, 39109DA11DD8A305004B5FAB /* LNPopupCloseButton+Private.h */, - 3947E1A81B61CDA40001178B /* LNPopupCloseButton.m */, + 3947E1A81B61CDA40001178B /* LNPopupCloseButton.mm */, 3907CDB924D9BD8A007C9300 /* LNPopupContentView+Private.h */, 3907CDB624D9BD6E007C9300 /* LNPopupContentView.m */, + 39B54FFE2D92D26300B474EC /* TransitionAnimators */, 3947E1B01B61CE4A0001178B /* LNPopupController.h */, - 3947E1B11B61CE4A0001178B /* LNPopupController.m */, + 3947E1B11B61CE4A0001178B /* LNPopupController.mm */, + 39FA8FCF2D9F84000068FD0D /* LNPopupDebug.h */, + 39FA8FD02D9F84000068FD0D /* LNPopupDebug.m */, 39599BAC1E02CDF4008EE386 /* LNPopupCustomBarViewController+Private.h */, 39599BA91E02CD65008EE386 /* LNPopupCustomBarViewController.m */, 394A85BB1B6306AE004FFC61 /* LNPopupItem+Private.h */, @@ -193,18 +241,20 @@ 39314A501B6AE7A400574D3C /* MarqueeLabel.h */, 39314A511B6AE7A400574D3C /* MarqueeLabel.m */, 396D62702610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.h */, - 396D62712610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.m */, + 396D62712610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.mm */, 399BA1D22A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.h */, - 399BA1D32A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.m */, + 399BA1D32A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.mm */, 39B3EB0B24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.h */, - 39B3EB0C24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.m */, - 3947E1A01B61CD1F0001178B /* UIViewController+LNPopupSupport.m */, + 39B3EB0C24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.mm */, + 3947E1A01B61CD1F0001178B /* UIViewController+LNPopupSupport.mm */, 394A85C71B63FB96004FFC61 /* UIViewController+LNPopupSupportPrivate.h */, - 394A85C81B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.m */, + 394A85C81B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.mm */, 39AC478F26C69AC9001D53C2 /* LNMath.h */, 39AC479026C69AC9001D53C2 /* LNMath.m */, 39A0DDB126F7894700E5D751 /* NSAttributedString+LNPopupSupport.h */, 39A0DDB226F7894700E5D751 /* NSAttributedString+LNPopupSupport.m */, + 39AF84EC2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.h */, + 39AF84ED2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.m */, ); name = Implementation; path = Private; @@ -213,6 +263,8 @@ 397AFBFE1F1A216400E7D95C /* GestureRecognizers */ = { isa = PBXGroup; children = ( + 3922006F2C663A03008AFD36 /* _LNPopupAddressInfo.h */, + 392200712C663A23008AFD36 /* _LNPopupAddressInfo.mm */, 397AFBF91F1A1ED200E7D95C /* LNForwardingDelegate.h */, 397AFBFA1F1A1ED200E7D95C /* LNForwardingDelegate.m */, 39222AD91F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.h */, @@ -225,6 +277,27 @@ name = GestureRecognizers; sourceTree = ""; }; + 39B54FFE2D92D26300B474EC /* TransitionAnimators */ = { + isa = PBXGroup; + children = ( + 39B54FFF2D92D29000B474EC /* _LNPopupTransitionAnimator.h */, + 39B550002D92D29000B474EC /* _LNPopupTransitionAnimator.mm */, + 39B550012D92D29000B474EC /* _LNPopupTransitionCloseAnimator.h */, + 39B550022D92D29000B474EC /* _LNPopupTransitionCloseAnimator.m */, + 39B550032D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.h */, + 39B550042D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.m */, + 39B550092D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.h */, + 39B5500A2D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.mm */, + 39B550072D92D29000B474EC /* _LNPopupTransitionOpenAnimator.h */, + 39B550082D92D29000B474EC /* _LNPopupTransitionOpenAnimator.m */, + 39B550052D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.h */, + 39B550062D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.m */, + 39B5500B2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.h */, + 39B5500C2D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.mm */, + ); + name = TransitionAnimators; + sourceTree = ""; + }; 39DB52DB1B5823330061C589 = { isa = PBXGroup; children = ( @@ -253,6 +326,7 @@ 390DD0101BB2EAC30064DB4A /* LNPopupContentView.h */, 39599BA81E02CD65008EE386 /* LNPopupCustomBarViewController.h */, 394A85B71B6304F5004FFC61 /* LNPopupItem.h */, + 399D37B62ADC672D00EA5038 /* LNPopupImageView.h */, 3947E19F1B61CD1F0001178B /* UIViewController+LNPopupSupport.h */, 39F8228726B80B6F0070DDBA /* SwiftRefinements.swift */, 46ECC2AE1BF31025005CE96C /* Info.plist */, @@ -272,23 +346,33 @@ 390DD0111BB2EAC30064DB4A /* LNPopupContentView.h in Headers */, 394A85B61B630409004FFC61 /* LNPopupBar.h in Headers */, 398C2903260CCDA6000690FB /* LNPopupContentView+Private.h in Headers */, + 39F9DECA2C84A211005CA5FB /* _LNPopupBase64Utils.hh in Headers */, 39599BAA1E02CD65008EE386 /* LNPopupCustomBarViewController.h in Headers */, + 39FA8FD12D9F84000068FD0D /* LNPopupDebug.h in Headers */, 399BA1D42A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.h in Headers */, 39C81A321B642DDD00D3B645 /* LNPopupItem.h in Headers */, 39A0DDB326F7894700E5D751 /* NSAttributedString+LNPopupSupport.h in Headers */, 3947E1A11B61CD1F0001178B /* UIViewController+LNPopupSupport.h in Headers */, 393E4EAA2670F2D000929E47 /* LNPopupBarAppearance.h in Headers */, - 39500DFF2B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.h in Headers */, 3947E1B21B61CE4A0001178B /* LNPopupController.h in Headers */, 39E9FE11275B984B00A47D61 /* LNPopupDefinitions.h in Headers */, 39B3EB0D24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.h in Headers */, 3947E1BA1B6300370001178B /* LNPopupBar+Private.h in Headers */, 398C2901260CCDA0000690FB /* UIViewController+LNPopupSupportPrivate.h in Headers */, + 39C553E02D8F2B3200F8D8B2 /* _LNPopupTransitionView.h in Headers */, 394005FC2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.h in Headers */, + 39AF84EF2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.h in Headers */, 397D9A172687474E005164AB /* _LNPopupBarBackgroundView.h in Headers */, - 399D37B82ADC672D00EA5038 /* _LNPopupBarShadowedImageView.h in Headers */, + 399D37B82ADC672D00EA5038 /* LNPopupImageView.h in Headers */, 397AFC051F1A229400E7D95C /* LNPopupInteractionPanGestureRecognizer.h in Headers */, 396A8DE826BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.h in Headers */, + 39B550142D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.h in Headers */, + 39B550152D92D29000B474EC /* _LNPopupTransitionOpenAnimator.h in Headers */, + 39B550162D92D29000B474EC /* _LNPopupTransitionCloseAnimator.h in Headers */, + 39B550172D92D29000B474EC /* _LNPopupTransitionAnimator.h in Headers */, + 39B550182D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.h in Headers */, + 39B550192D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.h in Headers */, + 39B5501A2D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.h in Headers */, 39E7A604200B5157007AF3AD /* _LNPopupSwizzlingUtils.h in Headers */, 396D62722610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.h in Headers */, 39314A521B6AE7A400574D3C /* MarqueeLabel.h in Headers */, @@ -296,6 +380,7 @@ 39599BAD1E02CDF4008EE386 /* LNPopupCustomBarViewController+Private.h in Headers */, 397AFBFB1F1A1ED200E7D95C /* LNForwardingDelegate.h in Headers */, 39222ADB1F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.h in Headers */, + 39C553E32D91925300F8D8B2 /* LNPopupImageView+Private.h in Headers */, 397AFC011F1A21DD00E7D95C /* LNPopupLongPressGestureRecognizer.h in Headers */, 390031692AC06FE10046D3DD /* _LNPopupBackgroundShadowView.h in Headers */, 394A85C11B630992004FFC61 /* _LNWeakRef.h in Headers */, @@ -335,7 +420,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 9999; - ORGANIZATIONNAME = "Leo Natan"; + ORGANIZATIONNAME = "Léo Natan"; TargetAttributes = { 39DB52E41B5823330061C589 = { CreatedOnToolsVersion = 7.0; @@ -344,7 +429,7 @@ }; }; buildConfigurationList = 39DB52DF1B5823330061C589 /* Build configuration list for PBXProject "LNPopupController" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 15.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -354,7 +439,6 @@ mainGroup = 39DB52DB1B5823330061C589; packageReferences = ( ); - productRefGroup = 39DB52E61B5823330061C589 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( @@ -379,32 +463,43 @@ buildActionMask = 2147483647; files = ( 39F8228826B80B6F0070DDBA /* SwiftRefinements.swift in Sources */, - 399D37B92ADC672D00EA5038 /* _LNPopupBarShadowedImageView.m in Sources */, + 399D37B92ADC672D00EA5038 /* LNPopupImageView.mm in Sources */, 39E7A605200B5157007AF3AD /* _LNPopupSwizzlingUtils.m in Sources */, 3900316A2AC06FE10046D3DD /* _LNPopupBackgroundShadowView.m in Sources */, 397AFC021F1A21DD00E7D95C /* LNPopupLongPressGestureRecognizer.m in Sources */, 39222ADC1F1A1C5800388E06 /* LNPopupOpenTapGestureRecognizer.m in Sources */, - 39500E002B4DD02300E20D08 /* _LNPopupBarAppearanceLegacySupport.m in Sources */, - 3947E1AA1B61CDA40001178B /* LNPopupCloseButton.m in Sources */, + 3975A5C42C663B520027FCDD /* _LNPopupAddressInfo.mm in Sources */, + 3947E1AA1B61CDA40001178B /* LNPopupCloseButton.mm in Sources */, 396A8DE926BEA36B005914B0 /* LNPopupBarAppearanceChainProxy.m in Sources */, - 39B3EB0E24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.m in Sources */, + 39C553DF2D8F2B3200F8D8B2 /* _LNPopupTransitionView.mm in Sources */, + 39B3EB0E24D4ECC40034B81D /* UIView+LNPopupSupportPrivate.mm in Sources */, + 39AF84EE2DA12D2D00E59C44 /* _LNPopupBarAppearanceLegacySupport.m in Sources */, 394A85C21B630992004FFC61 /* _LNWeakRef.m in Sources */, 394A85BA1B6304F5004FFC61 /* LNPopupItem.m in Sources */, - 3947E1B31B61CE4A0001178B /* LNPopupController.m in Sources */, + 3947E1B31B61CE4A0001178B /* LNPopupController.mm in Sources */, 397AFBFC1F1A1ED200E7D95C /* LNForwardingDelegate.m in Sources */, 39314A531B6AE7A400574D3C /* MarqueeLabel.m in Sources */, 3907CDB824D9BD6E007C9300 /* LNPopupContentView.m in Sources */, 391481BA1DCFA514002416D1 /* LNChevronView.m in Sources */, 394005FD2AC3C60900291421 /* _LNPopupBarBackgroundMaskView.m in Sources */, - 399BA1D52A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.m in Sources */, + 399BA1D52A9E975E00CA5167 /* _LNPopupUIBarAppearanceProxy.mm in Sources */, 397D9A182687474E005164AB /* _LNPopupBarBackgroundView.m in Sources */, - 3947E1A61B61CD650001178B /* LNPopupBar.m in Sources */, + 3947E1A61B61CD650001178B /* LNPopupBar.mm in Sources */, + 392200702C663A03008AFD36 /* _LNPopupAddressInfo.h in Sources */, 39A0DDB426F7894700E5D751 /* NSAttributedString+LNPopupSupport.m in Sources */, - 394A85C91B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.m in Sources */, + 394A85C91B63FE52004FFC61 /* UIViewController+LNPopupSupportPrivate.mm in Sources */, 397AFC061F1A229400E7D95C /* LNPopupInteractionPanGestureRecognizer.m in Sources */, - 393E4EA72670F12500929E47 /* LNPopupBarAppearance.m in Sources */, - 396D62732610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.m in Sources */, - 3947E1A21B61CD1F0001178B /* UIViewController+LNPopupSupport.m in Sources */, + 393E4EA72670F12500929E47 /* LNPopupBarAppearance.mm in Sources */, + 39B5500D2D92D29000B474EC /* _LNPopupTransitionAnimator.mm in Sources */, + 39B5500E2D92D29000B474EC /* _LNPopupTransitionCloseAnimator.m in Sources */, + 39B5500F2D92D29000B474EC /* _LNPopupTransitionOpenAnimator.m in Sources */, + 39B550102D92D29000B474EC /* _LNPopupTransitionPreferredOpenAnimator.mm in Sources */, + 39B550112D92D29000B474EC /* _LNPopupTransitionPreferredCloseAnimator.mm in Sources */, + 39B550122D92D29000B474EC /* _LNPopupTransitionGenericOpenAnimator.m in Sources */, + 39B550132D92D29000B474EC /* _LNPopupTransitionGenericCloseAnimator.m in Sources */, + 396D62732610A42000D03A42 /* UIContextMenuInteraction+LNPopupSupportPrivate.mm in Sources */, + 39FA8FD22D9F84000068FD0D /* LNPopupDebug.m in Sources */, + 3947E1A21B61CD1F0001178B /* UIViewController+LNPopupSupport.mm in Sources */, 39599BAB1E02CD65008EE386 /* LNPopupCustomBarViewController.m in Sources */, 39AC479226C69ACA001D53C2 /* LNMath.m in Sources */, ); @@ -460,8 +555,6 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MACH_O_TYPE = mh_dylib; MTL_ENABLE_DEBUG_INFO = YES; @@ -515,8 +608,6 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MACH_O_TYPE = mh_dylib; MTL_ENABLE_DEBUG_INFO = NO; @@ -539,8 +630,6 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; - DOCC_EXTRACT_OBJC_INFO_FOR_SWIFT_SYMBOLS = YES; - DOCC_EXTRACT_SWIFT_INFO_FOR_OBJC_SYMBOLS = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -549,10 +638,14 @@ INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.LeoNatan.LNPopupController; PRODUCT_NAME = LNPopupController; - RUN_DOCUMENTATION_COMPILER = YES; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -574,8 +667,6 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; - DOCC_EXTRACT_OBJC_INFO_FOR_SWIFT_SYMBOLS = YES; - DOCC_EXTRACT_SWIFT_INFO_FOR_OBJC_SYMBOLS = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -584,10 +675,14 @@ INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.LeoNatan.LNPopupController; PRODUCT_NAME = LNPopupController; - RUN_DOCUMENTATION_COMPILER = YES; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = YES; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/LNPopupController/LNPopupController/LNPopupBar.h b/LNPopupController/LNPopupController/LNPopupBar.h index af6b5db..6227b14 100644 --- a/LNPopupController/LNPopupController/LNPopupBar.h +++ b/LNPopupController/LNPopupController/LNPopupBar.h @@ -2,8 +2,8 @@ // LNPopupBar.h // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -11,6 +11,7 @@ #import #import #import +#import #define LN_UNAVAILABLE_PREVIEWING_MSG "Add context menu interaction or register for previewing directly on the popup bar view." @@ -73,7 +74,7 @@ NS_SWIFT_UI_ACTOR @property (nullable, nonatomic, copy, readonly) NSArray* trailingBarButtonItems; /// An image view displayed when the bar style is prominent. (read-only) -@property (nonatomic, strong, readonly) UIImageView* imageView; +@property (nonatomic, strong, readonly) LNPopupImageView* imageView; /// The popup bar style. @property (nonatomic, assign) LNPopupBarStyle barStyle UI_APPEARANCE_SELECTOR; @@ -83,8 +84,13 @@ NS_SWIFT_UI_ACTOR /// Use this property's value to determine, at runtime, what the result of `LNPopupBarStyleDefault` is. @property (nonatomic, assign, readonly) LNPopupBarStyle effectiveBarStyle; +/// In wide enough environments, such as iPadOS, limit the width of content of floating bars to a system-determined value. +/// +/// Defaults to `true`. +@property (nonatomic, assign) BOOL limitFloatingContentWidth; + /// Describes the appearance attributes for the popup bar to use. -@property (nonatomic, copy, null_resettable) LNPopupBarAppearance* standardAppearance UI_APPEARANCE_SELECTOR API_AVAILABLE(ios(13.0)); +@property (nonatomic, copy, null_resettable) LNPopupBarAppearance* standardAppearance UI_APPEARANCE_SELECTOR API_AVAILABLE(ios(13.0)); /// The popup bar's progress view style. @property (nonatomic, assign) LNPopupBarProgressViewStyle progressViewStyle UI_APPEARANCE_SELECTOR; @@ -110,66 +116,4 @@ NS_SWIFT_UI_ACTOR @end -#pragma mark Deprecations - -extern const UIBlurEffectStyle LNBackgroundStyleInherit LN_UNAVAILABLE_API("Use LNPopupBarAppearance instead."); - -@interface LNPopupBar (Deprecated) - -/// If `true`, the popup bar will automatically inherit its style from the bottom docking view. -@property (nonatomic, assign) BOOL inheritsVisualStyleFromDockingView LN_UNAVAILABLE_API("Use inheritsAppearanceFromDockingView instead."); - -/// The popup bar background style that specifies its appearance. -/// -/// Use `LNBackgroundStyleInherit` value to inherit the docking view's bar style if possible, or use a system default. -/// -/// Defaults to `LNBackgroundStyleInherit`. -@property (nonatomic, assign) UIBlurEffectStyle backgroundStyle LN_UNAVAILABLE_API("Use LNPopupBarAppearance.backgroundEffect instead."); - -/// The tint color to apply to the popup bar background. -@property (nullable, nonatomic, strong) UIColor* barTintColor LN_UNAVAILABLE_API("Use LNPopupBarAppearance.backgroundColor instead."); - -/// A Boolean value that indicates whether the popup bar is translucent (`true`) or not (`false`). -@property(nonatomic, assign, getter=isTranslucent) BOOL translucent LN_UNAVAILABLE_API("Use LNPopupBarAppearance.configureWithOpaqueBackground() instead."); - -/// Display attributes for the popup bar’s title text. -/// -/// You may specify the font, text color, and shadow properties for the title in the text attributes dictionary, using the keys found in `NSAttributedString.h`. -@property (nullable, nonatomic, copy) NSDictionary* titleTextAttributes LN_UNAVAILABLE_API("Use LNPopupBarAppearance.titleTextAttributes instead."); - -/// Display attributes for the popup bar’s subtitle text. -/// -/// You may specify the font, text color, and shadow properties for the title in the text attributes dictionary, using the keys found in `NSAttributedString.h`. -@property (nullable, nonatomic, copy) NSDictionary* subtitleTextAttributes LN_UNAVAILABLE_API("Use LNPopupBarAppearance.subtitleTextAttributes instead."); - -/// When enabled, titles and subtitles that are longer than the space available will scroll text over time. -/// -/// Defaults to `false`. -@property (nonatomic, assign) BOOL marqueeScrollEnabled LN_UNAVAILABLE_API("Use LNPopupBarAppearance.marqueeScrollEnabled instead."); - -/// The scroll rate, in points, of the title and subtitle marquee animation. -/// -/// Defaults to `30`. -@property (nonatomic, assign) CGFloat marqueeScrollRate LN_UNAVAILABLE_API("Use LNPopupBarAppearance.marqueeScrollRate instead."); - -/// The delay, in seconds, before starting the title and subtitle marquee animation. -/// -/// Defaults to `2`. -@property (nonatomic, assign) NSTimeInterval marqueeScrollDelay LN_UNAVAILABLE_API("Use LNPopupBarAppearance.marqueeScrollDelay instead."); - -/// When enabled, the title and subtitle marquee scroll animations will be coordinated. -/// -/// If either the title or subtitle of the current popup item change, the animation will reset so the two can scroll together. -/// -/// Defaults to `true`. -@property (nonatomic, assign) BOOL coordinateMarqueeScroll LN_UNAVAILABLE_API("Use LNPopupBarAppearance.coordinateMarqueeScroll instead."); - -/// An array of custom bar button items to display on the left side. (read-only) -@property (nullable, nonatomic, copy, readonly) NSArray* leftBarButtonItems LN_UNAVAILABLE_API("Use leadingBarButtonItems instead."); - -/// An array of custom bar button items to display on the right side. (read-only) -@property (nullable, nonatomic, copy, readonly) NSArray* rightBarButtonItems LN_UNAVAILABLE_API("Use barButtonItems or trailingBarButtonItems instead."); - -@end - NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/LNPopupBarAppearance.h b/LNPopupController/LNPopupController/LNPopupBarAppearance.h index 07423c6..d630293 100644 --- a/LNPopupController/LNPopupController/LNPopupBarAppearance.h +++ b/LNPopupController/LNPopupController/LNPopupBarAppearance.h @@ -2,8 +2,8 @@ // LNPopupBarAppearance.h // LNPopupController // -// Created by Leo Natan on 6/9/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-06-20. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/LNPopupCloseButton.h b/LNPopupController/LNPopupController/LNPopupCloseButton.h index a288bb3..1ca3d27 100644 --- a/LNPopupController/LNPopupController/LNPopupCloseButton.h +++ b/LNPopupController/LNPopupController/LNPopupCloseButton.h @@ -2,8 +2,8 @@ // LNPopupCloseButton.h // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -36,11 +36,16 @@ NS_SWIFT_UI_ACTOR @interface LNPopupCloseButton : UIButton /// Gets or sets the style of the popup close button. Has the same effect as setting the `LNPopupContentView.popupCloseButtonStyle` property of the popup content view. -@property (nonatomic) LNPopupCloseButtonStyle style UI_APPEARANCE_SELECTOR; +@property (nonatomic, assign) LNPopupCloseButtonStyle style UI_APPEARANCE_SELECTOR; + +/// The effective popup close button style used by the system. (read-only) +/// +/// Use this property's value to determine, at runtime, what the result of `LNPopupCloseButtonStyleDefault` is. +@property (nonatomic, assign, readonly) LNPopupCloseButtonStyle effectiveStyle; /// The button’s background view. (read-only) /// -/// The value of this property will be `nil` if ``style`` is not set to `LNPopupCloseButtonStyleRound`. +/// The value of this property will be `nil` if `style` is set to any value other than `LNPopupCloseButtonStyleRound`. /// /// @note Although this property is read-only, its own properties are read/write. Use these properties to configure the appearance and behavior of the button’s background view. @property (nonatomic, strong, readonly) UIVisualEffectView* backgroundView; diff --git a/LNPopupController/LNPopupController/LNPopupContentView.h b/LNPopupController/LNPopupController/LNPopupContentView.h index 2b50f3a..073f394 100644 --- a/LNPopupController/LNPopupController/LNPopupContentView.h +++ b/LNPopupController/LNPopupController/LNPopupContentView.h @@ -2,8 +2,8 @@ // LNPopupItem.h // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-09-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -25,7 +25,12 @@ NS_SWIFT_UI_ACTOR /// The popup close button style. /// /// Defaults to `LNPopupCloseButtonStyleDefault`. -@property (nonatomic) LNPopupCloseButtonStyle popupCloseButtonStyle UI_APPEARANCE_SELECTOR; +@property (nonatomic, assign) LNPopupCloseButtonStyle popupCloseButtonStyle UI_APPEARANCE_SELECTOR; + +/// The effective popup close button style used by the system. (read-only) +/// +/// Use this property's value to determine, at runtime, what the result of `LNPopupCloseButtonStyleDefault` is. +@property (nonatomic, assign, readonly) LNPopupCloseButtonStyle effectivePopupCloseButtonStyle; /// The popup close button. (read-only) @property (nonatomic, strong, readonly) LNPopupCloseButton* popupCloseButton; @@ -44,24 +49,4 @@ NS_SWIFT_UI_ACTOR @end -#pragma mark Deprecations - -extern const UIBlurEffectStyle LNBackgroundStyleInherit LN_UNAVAILABLE_API("Use backgroundEffect instead."); - -@interface LNPopupContentView (Deprecated) - -/// Attempt to automatically move the popup close button under top bars, such as navigation bars. -/// -/// Note: No longer supported. Instead, implement `UIViewController.positionPopupCloseButton()` and position the button in your content controller's view hierarchy. -@property (nonatomic) BOOL popupCloseButtonAutomaticallyUnobstructsTopBars LN_UNAVAILABLE_API("No longer supported. Instead, implement UIViewController.positionPopupCloseButton() and position the button in your content controller's view hierarchy."); - -/// The popup content view background style, used when the popup content controller's view has transparency. -/// -/// Use `LNBackgroundStyleInherit` value to inherit the popup bar's background style if possible. -/// -/// Defaults to `LNBackgroundStyleInherit`. -@property (nonatomic, assign) UIBlurEffectStyle backgroundStyle LN_UNAVAILABLE_API("Use backgroundEffect instead."); - -@end - NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/LNPopupCustomBarViewController.h b/LNPopupController/LNPopupController/LNPopupCustomBarViewController.h index 208cd30..7da1e52 100644 --- a/LNPopupController/LNPopupController/LNPopupCustomBarViewController.h +++ b/LNPopupController/LNPopupController/LNPopupCustomBarViewController.h @@ -2,8 +2,8 @@ // LNPopupBarContentViewController.h // LNPopupController // -// Created by Leo Natan on 15/12/2016. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2016-12-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/LNPopupDefinitions.h b/LNPopupController/LNPopupController/LNPopupDefinitions.h index 2c7c65c..cf3cee5 100644 --- a/LNPopupController/LNPopupController/LNPopupDefinitions.h +++ b/LNPopupController/LNPopupController/LNPopupDefinitions.h @@ -2,8 +2,8 @@ // LNPopupDefinitions.h // LNPopupController // -// Created by Leo Natan on 12/4/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-12-16. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #ifndef LNPopupDefinitions_h diff --git a/LNPopupController/LNPopupController/LNPopupImageView.h b/LNPopupController/LNPopupController/LNPopupImageView.h new file mode 100644 index 0000000..a4a4026 --- /dev/null +++ b/LNPopupController/LNPopupController/LNPopupImageView.h @@ -0,0 +1,27 @@ +// +// LNPopupImageView.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A specialized `UIImageView` subclass, allowing setting a shadow and corner radius. +/// +/// When used inside a popup content view, instances of this class are especially suited as image transition targets. +/// +/// See `UIViewController.viewForPopupTransition(from:to:)`. +@interface LNPopupImageView : UIImageView + +/// The corner radius of the image view. +@property (nonatomic, assign) CGFloat cornerRadius; +/// The shadow displayed underneath the image view. +@property (nonatomic, copy) NSShadow* shadow; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/LNPopupItem.h b/LNPopupController/LNPopupController/LNPopupItem.h index ceb390e..82cca51 100644 --- a/LNPopupController/LNPopupController/LNPopupItem.h +++ b/LNPopupController/LNPopupController/LNPopupItem.h @@ -2,8 +2,8 @@ // LNPopupItem.h // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNChevronView.h b/LNPopupController/LNPopupController/Private/LNChevronView.h index 5095749..4959b6a 100644 --- a/LNPopupController/LNPopupController/Private/LNChevronView.h +++ b/LNPopupController/LNPopupController/Private/LNChevronView.h @@ -1,8 +1,8 @@ // // LNChevronView.h // -// Created by Leo Natan on 16/9/16. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2016-12-02. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #define LNChevronView __LNChevronView diff --git a/LNPopupController/LNPopupController/Private/LNChevronView.m b/LNPopupController/LNPopupController/Private/LNChevronView.m index 0eafba4..474e95a 100644 --- a/LNPopupController/LNPopupController/Private/LNChevronView.m +++ b/LNPopupController/LNPopupController/Private/LNChevronView.m @@ -1,8 +1,8 @@ // // LNChevronView.m // -// Created by Leo Natan on 16/9/16. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2016-12-02. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNChevronView.h" diff --git a/LNPopupController/LNPopupController/Private/LNForwardingDelegate.h b/LNPopupController/LNPopupController/Private/LNForwardingDelegate.h index e41c095..d8d7fba 100644 --- a/LNPopupController/LNPopupController/Private/LNForwardingDelegate.h +++ b/LNPopupController/LNPopupController/Private/LNForwardingDelegate.h @@ -2,8 +2,8 @@ // LNForwardingDelegate.h // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -12,4 +12,6 @@ @property (nonatomic, weak) id forwardedDelegate; ++ (BOOL)isCallerUIKit:(NSArray*)callStackReturnAddresses; + @end diff --git a/LNPopupController/LNPopupController/Private/LNForwardingDelegate.m b/LNPopupController/LNPopupController/Private/LNForwardingDelegate.m index 65e7448..6884f6c 100644 --- a/LNPopupController/LNPopupController/Private/LNForwardingDelegate.m +++ b/LNPopupController/LNPopupController/Private/LNForwardingDelegate.m @@ -2,11 +2,12 @@ // LNForwardingDelegate.m // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNForwardingDelegate.h" +#import "_LNPopupAddressInfo.h" @implementation LNForwardingDelegate @@ -37,4 +38,12 @@ return [self.forwardedDelegate methodSignatureForSelector:aSelector]; } ++ (BOOL)isCallerUIKit:(NSArray *)callStackReturnAddresses +{ + NSUInteger addr = [callStackReturnAddresses[1] unsignedIntegerValue]; + _LNPopupAddressInfo* addrInfo = [[_LNPopupAddressInfo alloc] initWithAddress:addr]; + + return [addrInfo.image hasPrefix:@"UIKit"]; +} + @end diff --git a/LNPopupController/LNPopupController/Private/LNMath.h b/LNPopupController/LNPopupController/Private/LNMath.h index b2e2cbc..4dd2556 100644 --- a/LNPopupController/LNPopupController/Private/LNMath.h +++ b/LNPopupController/LNPopupController/Private/LNMath.h @@ -2,13 +2,19 @@ // LNMath.h // LNPopupController // -// Created by Leo Natan on 8/6/21. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-08-06. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #ifndef C__Math_h #define C__Math_h +#import + +CF_EXTERN_C_BEGIN + extern double _ln_clamp(double v, double lo, double hi); +CF_EXTERN_C_END + #endif /* C__Math_h */ diff --git a/LNPopupController/LNPopupController/Private/LNMath.m b/LNPopupController/LNPopupController/Private/LNMath.m index 258c2fb..07dd4af 100644 --- a/LNPopupController/LNPopupController/Private/LNMath.m +++ b/LNPopupController/LNPopupController/Private/LNMath.m @@ -2,8 +2,8 @@ // LNMath. // LNPopupController // -// Created by Leo Natan on 8/6/21. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-08-11. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #include "LNMath.h" diff --git a/LNPopupController/LNPopupController/Private/LNPopupBar+Private.h b/LNPopupController/LNPopupController/Private/LNPopupBar+Private.h index 1aca446..c192aeb 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupBar+Private.h +++ b/LNPopupController/LNPopupController/Private/LNPopupBar+Private.h @@ -2,8 +2,8 @@ // LNPopupBar+Private.h // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -13,6 +13,8 @@ #import "_LNPopupBackgroundShadowView.h" #import "_LNPopupBarBackgroundMaskView.h" +CF_EXTERN_C_BEGIN + extern const CGFloat LNPopupBarHeightCompact; extern const CGFloat LNPopupBarHeightProminent; extern const CGFloat LNPopupBarHeightFloating; @@ -39,6 +41,7 @@ inline __attribute__((always_inline)) LNPopupBarStyle _LNPopupResolveBarStyleFro - (void)_traitCollectionForPopupBarDidChange:(LNPopupBar*)bar; - (void)_popupBarMetricsDidChange:(LNPopupBar*)bar; +- (void)_popupBarMetricsDidChange:(LNPopupBar*)bar shouldLayout:(BOOL)layout; - (void)_popupBarStyleDidChange:(LNPopupBar*)bar; - (void)_popupBar:(LNPopupBar*)bar updateCustomBarController:(LNPopupCustomBarViewController*)customController cleanup:(BOOL)cleanup; - (void)_removeInteractionGestureForPopupBar:(LNPopupBar*)bar; @@ -64,7 +67,7 @@ inline __attribute__((always_inline)) LNPopupBarStyle _LNPopupResolveBarStyleFro @property (nonatomic, readonly, strong) LNPopupBarAppearance* activeAppearance API_AVAILABLE(ios(13.0)); @property (nonatomic, readonly, strong) LNPopupBarAppearanceChainProxy* activeAppearanceChain API_AVAILABLE(ios(13.0)); -- (void)_recalcActiveAppearanceChain API_AVAILABLE(ios(13.0)); +- (void)_recalcActiveAppearanceChain; @property (nonatomic, strong) UIImageView* shadowView; @property (nonatomic, strong) UIImageView* bottomShadowView; @@ -77,6 +80,8 @@ inline __attribute__((always_inline)) LNPopupBarStyle _LNPopupResolveBarStyleFro @property (nonatomic, copy) NSAttributedString* attributedTitle; @property (nonatomic, copy) NSAttributedString* attributedSubtitle; +@property (nonatomic) NSDirectionalEdgeInsets _hackyMargins; + @property (nonatomic, strong) UIImage* image; @property (nonatomic, strong) UIView* highlightView; @@ -113,11 +118,11 @@ inline __attribute__((always_inline)) LNPopupBarStyle _LNPopupResolveBarStyleFro @property (nonatomic) BOOL acceptsSizing; -@property (nonatomic) BOOL _applySwiftUILayoutFixes; +@property (nonatomic) BOOL _applySwiftUILayoutFixes API_AVAILABLE(ios(13.0)); -@property (nonatomic, strong) UIFont* swiftuiInheritedFont; +@property (nonatomic, strong) UIFont* swiftuiInheritedFont API_AVAILABLE(ios(13.0)); -@property (nonatomic, strong) UIView* swiftuiTitleContentView; +@property (nonatomic, strong) UIView* swiftuiTitleContentView API_AVAILABLE(ios(13.0)); @property (nonatomic, strong) UIViewController* swiftuiImageController API_AVAILABLE(ios(13.0)); @property (nonatomic, strong) UIViewController* swiftuiHiddenLeadingController API_AVAILABLE(ios(13.0)); @@ -135,4 +140,9 @@ inline __attribute__((always_inline)) LNPopupBarStyle _LNPopupResolveBarStyleFro - (void)_appearanceDidChange; ++ (BOOL)isCatalystApp; +- (BOOL)isWidePad; + @end + +CF_EXTERN_C_END diff --git a/LNPopupController/LNPopupController/Private/LNPopupBar.m b/LNPopupController/LNPopupController/Private/LNPopupBar.mm similarity index 76% rename from LNPopupController/LNPopupController/Private/LNPopupBar.m rename to LNPopupController/LNPopupController/Private/LNPopupBar.mm index 64d53c8..5fe6414 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupBar.m +++ b/LNPopupController/LNPopupController/Private/LNPopupBar.mm @@ -2,38 +2,22 @@ // LNPopupBar.m // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupBar+Private.h" #import "LNPopupCustomBarViewController+Private.h" #import "MarqueeLabel.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" #import "NSAttributedString+LNPopupSupport.h" -#import "_LNPopupBarShadowedImageView.h" +#import "LNPopupImageView+Private.h" +#import "UIView+LNPopupSupportPrivate.h" #import "_LNPopupBarAppearanceLegacySupport.h" #ifdef DEBUG -static NSUserDefaults* __LNDebugUserDefaults(void) -{ - static NSUserDefaults* rv = nil; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - SEL sel = NSSelectorFromString(@"settingDefaults"); - if([NSUserDefaults respondsToSelector:sel]) - { - rv = [NSUserDefaults valueForKey:@"settingDefaults"]; - } - else - { - rv = NSUserDefaults.standardUserDefaults; - } - }); - - return rv; -} +#import "LNPopupDebug.h" static BOOL _LNEnableBarLayoutDebug(void) { @@ -66,6 +50,11 @@ CGFloat _LNPopupBarHeightForPopupBar(LNPopupBar* popupBar) }); additionalHeight = [additionalHeightMapping[popupBar.traitCollection.preferredContentSizeCategory] doubleValue]; + if(popupBar.effectiveBarStyle == LNPopupBarStyleFloating && popupBar.isWidePad) + { + additionalHeight += 8; + } + switch(popupBar.resolvedStyle) { case LNPopupBarStyleCompact: @@ -78,17 +67,15 @@ CGFloat _LNPopupBarHeightForPopupBar(LNPopupBar* popupBar) } #ifndef LNPopupControllerEnforceStrictClean -//_effectWithStyle:tintColor:invertAutomaticStyle: -static NSString* const _eWSti = @"X2VmZmVjdFdpdGhTdHlsZTp0aW50Q29sb3I6aW52ZXJ0QXV0b21hdGljU3R5bGU6"; static SEL _effectWithStyle_tintColor_invertAutomaticStyle_SEL; static id(*_effectWithStyle_tintColor_invertAutomaticStyle)(id, SEL, NSUInteger, UIColor*, BOOL); __attribute__((constructor)) static void __setupFunction(void) { - _effectWithStyle_tintColor_invertAutomaticStyle_SEL = NSSelectorFromString(_LNPopupDecodeBase64String(_eWSti)); + _effectWithStyle_tintColor_invertAutomaticStyle_SEL = NSSelectorFromString(LNPopupHiddenString("_effectWithStyle:tintColor:invertAutomaticStyle:")); Method m = class_getClassMethod(UIBlurEffect.class, _effectWithStyle_tintColor_invertAutomaticStyle_SEL); - _effectWithStyle_tintColor_invertAutomaticStyle = (void*)method_getImplementation(m); + _effectWithStyle_tintColor_invertAutomaticStyle = reinterpret_cast(method_getImplementation(m)); } #endif @@ -98,8 +85,80 @@ static void __setupFunction(void) @interface _LNPopupBarTitlesView : UIStackView @end @implementation _LNPopupBarTitlesView @end +@interface _LNPopupTitleLabelWrapper: UIView + +@property (nonatomic, strong) UILabel* wrapped; +@property (nonatomic, strong) NSLayoutConstraint* wrappedWidthConstraint; + +@end + +@implementation _LNPopupTitleLabelWrapper + ++ (instancetype)wrapperForLabel:(UILabel*)wrapped +{ + _LNPopupTitleLabelWrapper* rv = [[_LNPopupTitleLabelWrapper alloc] initWithFrame:wrapped.frame]; + rv.wrapped = wrapped; + + rv.translatesAutoresizingMaskIntoConstraints = wrapped.translatesAutoresizingMaskIntoConstraints; + [rv addSubview:wrapped]; + + rv.wrappedWidthConstraint = [wrapped.widthAnchor constraintEqualToConstant:rv.bounds.size.width]; + + [NSLayoutConstraint activateConstraints:@[ + [rv.leadingAnchor constraintEqualToAnchor:wrapped.leadingAnchor], + [rv.heightAnchor constraintEqualToAnchor:wrapped.heightAnchor], + rv->_wrappedWidthConstraint + ]]; + + return rv; +} + +- (void)setBounds:(CGRect)bounds +{ + [super setBounds:bounds]; + + if(_wrappedWidthConstraint.constant == bounds.size.width) + { + return; + } + + if(UIView.inheritedAnimationDuration == 0.0) + { + _wrappedWidthConstraint.constant = bounds.size.width; + [_wrapped layoutSubviews]; + } + else + { + [UIView transitionWithView:_wrapped + duration:UIView.inheritedAnimationDuration / 2.0 + options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveEaseOut + animations:^{ + _wrappedWidthConstraint.constant = bounds.size.width; + [_wrapped layoutSubviews]; + } completion:nil]; + } +} + +@end + @interface _LNPopupBarShadowView : UIImageView @end -@implementation _LNPopupBarShadowView @end +@implementation _LNPopupBarShadowView + +#if DEBUG + +- (void)setAlpha:(CGFloat)alpha +{ + [super setAlpha:alpha]; +} + +- (void)setHidden:(BOOL)hidden +{ + [super setHidden:hidden]; +} + +#endif + +@end @protocol _LNPopupToolbarLayoutDelegate @@ -118,12 +177,9 @@ static void __setupFunction(void) { UIView* rv = [super hitTest:point withEvent:event]; - if(rv != nil && rv != self) + if(rv != nil && [rv isKindOfClass:UIControl.class] == NO && [NSStringFromClass(rv.class) containsString:@"BarItemView"] == NO) { - CGRect frameInBarCoords = [self convertRect:rv.bounds fromView:rv]; - CGRect instetFrame = CGRectInset(frameInBarCoords, 2, 0); - - return CGRectContainsPoint(instetFrame, point) ? rv : self; + rv = nil; } return rv; @@ -136,8 +192,6 @@ static void __setupFunction(void) //On iOS 11 and above reset the semantic content attribute to make sure it propagades to all subviews. [self setSemanticContentAttribute:self.semanticContentAttribute]; - [self.subviews.firstObject setAlpha:0.0]; - [self._layoutDelegate _toolbarDidLayoutSubviews]; } @@ -165,7 +219,7 @@ static void __setupFunction(void) @end -@protocol __MarqueeLabelType +@protocol LNMarqueeLabel - (void)resetLabel; - (void)unpauseLabel; @@ -182,8 +236,8 @@ static void __setupFunction(void) @end -@interface __FakeMarqueeLabel : UILabel <__MarqueeLabelType> @end -@implementation __FakeMarqueeLabel +@interface LNNonMarqueeLabel : UILabel @end +@implementation LNNonMarqueeLabel - (void)resetLabel {} - (void)unpauseLabel {} @@ -197,13 +251,15 @@ static void __setupFunction(void) @end -@interface MarqueeLabel () <__MarqueeLabelType> @end +@interface MarqueeLabel () @end const CGFloat LNPopupBarHeightCompact = 40.0; const CGFloat LNPopupBarHeightProminent = 64.0; const CGFloat LNPopupBarHeightFloating = 64.0; const CGFloat LNPopupBarProminentImageWidth = 48.0; const CGFloat LNPopupBarFloatingImageWidth = 40.0; +const CGFloat LNPopupBarFloatingPadImageWidth = 44.0; +const CGFloat LNPopupBarFloatingPadWidthLimit = 954.0; static BOOL __animatesItemSetter = NO; @@ -223,14 +279,14 @@ __attribute__((objc_direct_members)) { BOOL _delaysBarButtonItemLayout; - _LNPopupBarShadowedImageView* _imageView; + LNPopupImageView* _imageView; _LNPopupBarTitlesView* _titlesView; NSLayoutConstraint* _titlesViewLeadingConstraint; NSLayoutConstraint* _titlesViewTrailingConstraint; - UILabel<__MarqueeLabelType>* _titleLabel; - UILabel<__MarqueeLabelType>* _subtitleLabel; + UILabel* _titleLabel; + UILabel* _subtitleLabel; BOOL _needsLabelsLayout; BOOL _marqueePaused; @@ -304,7 +360,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu [self _layoutBarButtonItems]; _needsLabelsLayout = YES; - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { [self _fixupSwiftUIControllersWithBarStyle]; } @@ -319,6 +375,14 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu } } +- (void)set_hackyMargins:(NSDirectionalEdgeInsets)_hackyMargins +{ + __hackyMargins = _hackyMargins; + + [self _setNeedsTitleLayoutRemovingLabels:NO]; + [self setNeedsLayout]; +} + - (LNPopupBarStyle)effectiveBarStyle { return _resolvedStyle; @@ -347,14 +411,10 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu self.preservesSuperviewLayoutMargins = YES; self.clipsToBounds = NO; - if (@available(iOS 13.4, *)) - { - UIPointerInteraction* pointerInteraction = [[UIPointerInteraction alloc] initWithDelegate:self]; - [self addInteraction:pointerInteraction]; - } + self.limitFloatingContentWidth = YES; _inheritsAppearanceFromDockingView = YES; - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { _standardAppearance = [LNPopupBarAppearance new]; } @@ -373,6 +433,12 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _contentView.clipsToBounds = NO; [self addSubview:_contentView]; + if(@available(iOS 13.4, *)) + { + UIPointerInteraction* pointerInteraction = [[UIPointerInteraction alloc] initWithDelegate:self]; + [_contentView addInteraction:pointerInteraction]; + } + _contentMaskView = [UIView new]; _contentMaskView.backgroundColor = UIColor.whiteColor; _contentMaskView.frame = self.bounds; @@ -392,37 +458,26 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _toolbar = [[_LNPopupToolbar alloc] initWithFrame:CGRectMake(0, 0, 400, 44)]; _toolbar._layoutDelegate = self; - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { [_toolbar.standardAppearance configureWithTransparentBackground]; + +#if DEBUG + if(_LNEnableBarLayoutDebug()) + { + _toolbar.standardAppearance.backgroundColor = [UIColor.yellowColor colorWithAlphaComponent:0.7]; + _toolbar.layer.borderColor = UIColor.blackColor.CGColor; + _toolbar.layer.borderWidth = 1.0; + } +#endif + _toolbar.compactAppearance = _toolbar.standardAppearance; } else { _toolbar.translucent = NO; _toolbar.backgroundColor = UIColor.clearColor; - - // Fallback on earlier versions } -#if DEBUG - if(_LNEnableBarLayoutDebug()) - { - if (@available(iOS 13.0, *)) - { - _toolbar.standardAppearance.backgroundColor = [UIColor.yellowColor colorWithAlphaComponent:0.7]; - } - else - { - _toolbar.barTintColor = [UIColor.yellowColor colorWithAlphaComponent:0.7]; - } - _toolbar.layer.borderColor = UIColor.blackColor.CGColor; - _toolbar.layer.borderWidth = 1.0; - } -#endif - if (@available(iOS 13.0, *)) - { - _toolbar.compactAppearance = _toolbar.standardAppearance; - } if(@available(iOS 15.0, *)) { _toolbar.scrollEdgeAppearance = nil; @@ -461,16 +516,15 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _needsLabelsLayout = YES; - _imageView = [_LNPopupBarShadowedImageView new]; + _imageView = [[LNPopupImageView alloc] initWithContainingPopupBar:self];; _imageView.autoresizingMask = UIViewAutoresizingNone; _imageView.contentMode = UIViewContentModeScaleAspectFit; _imageView.accessibilityTraits = UIAccessibilityTraitImage; _imageView.isAccessibilityElement = YES; - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { _imageView.layer.cornerCurve = kCACornerCurveContinuous; } - _imageView.layer.masksToBounds = YES; _imageView.cornerRadius = 6; // support smart invert and therefore do not invert image view colors @@ -496,10 +550,8 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _wantsBackgroundCutout = YES; - if(@available(iOS 13.0, *)) - { - [self _recalcActiveAppearanceChain]; - } + [self _recalcActiveAppearanceChain]; + [self _appearanceDidChange]; } return self; @@ -518,7 +570,12 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu [self _appearanceDidChange]; } - if(previousTraitCollection.preferredContentSizeCategory == nil || UIContentSizeCategoryCompareToCategory(previousTraitCollection.preferredContentSizeCategory, self.traitCollection.preferredContentSizeCategory) != NSOrderedSame) + if(UIContentSizeCategoryCompareToCategory(previousTraitCollection.preferredContentSizeCategory, self.traitCollection.preferredContentSizeCategory) != NSOrderedSame) + { + [self._barDelegate _popupBarMetricsDidChange:self]; + } + + if(_LNPopupBarHeightForPopupBar(self) != self.bounds.size.height) { [self._barDelegate _popupBarMetricsDidChange:self]; } @@ -556,6 +613,8 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu return; } + _customBarViewController.view.autoresizingMask = UIViewAutoresizingNone; + CGRect frame = _contentView.bounds; frame.size.height = _customBarViewController.preferredContentSize.height; _customBarViewController.view.frame = frame; @@ -585,6 +644,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu CGFloat barHeight = _LNPopupBarHeightForPopupBar(self); frame.size.height = barHeight; + frame = UIEdgeInsetsInsetRect(frame, _LNEdgeInsetsFromDirectionalEdgeInsets(self, __hackyMargins)); [_backgroundView setFrame:frame]; _backgroundView.layer.mask.frame = _backgroundView.bounds; @@ -592,13 +652,20 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu BOOL isFloating = _resolvedStyle == LNPopupBarStyleFloating; BOOL isProminent = _resolvedStyle == LNPopupBarStyleProminent; BOOL isCustom = _resolvedStyle == LNPopupBarStyleCustom; - BOOL isRTL = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft; + BOOL isRTL = self.effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft; CGRect contentFrame; if(isFloating) { - CGFloat inset = self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular ? 30 : 12; - contentFrame = CGRectOffset(UIEdgeInsetsInsetRect(frame, UIEdgeInsetsMake(4, MAX(self.safeAreaInsets.left + 12, inset), 4, MAX(self.safeAreaInsets.right + 12, inset))), 0, -2); + CGFloat inset = self.limitFloatingContentWidth || self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact ? 12 : 30; + contentFrame = UIEdgeInsetsInsetRect(frame, UIEdgeInsetsMake(4, MAX(self.safeAreaInsets.left + 12, inset), 4, MAX(self.safeAreaInsets.right + 12, inset))); + if(self.limitFloatingContentWidth == YES && contentFrame.size.width > LNPopupBarFloatingPadWidthLimit && UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + //On iPadOS, constrain floating bar width to 818pt. + CGFloat d = (contentFrame.size.width - LNPopupBarFloatingPadWidthLimit) / 2; + contentFrame = UIEdgeInsetsInsetRect(contentFrame, UIEdgeInsetsMake(0, d, 0, d)); + } + contentFrame = CGRectOffset(contentFrame, 0, -2); _contentView.cornerRadius = 14; @@ -685,10 +752,6 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu [_contentView.contentView insertSubview:_imageView aboveSubview:_toolbar]; [_contentView.contentView insertSubview:_titlesView aboveSubview:_imageView]; - if(_customBarViewController != nil) - { - [_contentView.contentView insertSubview:_customBarViewController.view aboveSubview:_bottomShadowView]; - } UIScreen* screen = self.window.screen ?: UIScreen.mainScreen; CGFloat h = 1 / screen.scale; @@ -723,10 +786,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _progressView.frame = CGRectMake(cornerRadius + offset, height - 2.5, width - 2 * cornerRadius, 1.5); } - - [self _layoutTitles]; - - CGFloat titleSpacing = 1 + (1 / MAX(1, self.window.screen.scale)); + CGFloat titleSpacing = 1 + (1 / MAX(1, screen.scale)); if(_resolvedStyle == LNPopupBarStyleCompact) { titleSpacing = 0; @@ -765,27 +825,15 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _titlesView.spacing = titleSpacing; - [UIView performWithoutAnimation:^{ - [self.contentView layoutIfNeeded]; - [self.contentView updateConstraintsIfNeeded]; - [_titlesView layoutIfNeeded]; - [self.contentView layoutIfNeeded]; - }]; + [self _layoutTitles]; _inLayout = NO; } - (void)willMoveToWindow:(UIWindow *)newWindow { - static NSString* willRotate = nil; - static NSString* didRotate = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - //UIWindowWillRotateNotification - willRotate = _LNPopupDecodeBase64String(@"VUlXaW5kb3dXaWxsUm90YXRlTm90aWZpY2F0aW9u"); - //UIWindowDidRotateNotification - didRotate = _LNPopupDecodeBase64String(@"VUlXaW5kb3dEaWRSb3RhdGVOb3RpZmljYXRpb24="); - }); + static NSString* willRotate = LNPopupHiddenString("UIWindowWillRotateNotification"); + static NSString* didRotate = LNPopupHiddenString("UIWindowDidRotateNotification"); if(self.window) { @@ -822,16 +870,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu [self setWantsBackgroundCutout:YES allowImplicitAnimations:YES]; } -- (NSString*)_effectGroupingIdentifierKey -{ - static NSString* gN = @"Z3JvdXBOYW1l"; - static NSString* rv = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - rv = _LNPopupDecodeBase64String(gN); - }); - return rv; -} +static NSString* __ln_effectGroupingIdentifierKey = LNPopupHiddenString("groupName"); - (void)_applyGroupingIdentifier:(NSString*)groupingIdentifier toVisualEffectView:(UIVisualEffectView*)visualEffectView { @@ -840,12 +879,12 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu return; } - if([[visualEffectView valueForKey:self._effectGroupingIdentifierKey] isEqualToString:groupingIdentifier]) + if([[visualEffectView valueForKey:__ln_effectGroupingIdentifierKey] isEqualToString:groupingIdentifier]) { return; } - [visualEffectView setValue:groupingIdentifier ?: [NSString stringWithFormat:@"<%@:%p> Backdrop Group", self.class, self] forKey:self._effectGroupingIdentifierKey]; + [visualEffectView setValue:groupingIdentifier ?: [NSString stringWithFormat:@"<%@:%p> Backdrop Group", self.class, self] forKey:__ln_effectGroupingIdentifierKey]; } - (void)_applyGroupingIdentifierToVisualEffectView:(UIVisualEffectView*)visualEffectView @@ -855,7 +894,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu - (NSString *)effectGroupingIdentifier { - return [self.backgroundView.effectView valueForKey:self._effectGroupingIdentifierKey]; + return [self.backgroundView.effectView valueForKey:__ln_effectGroupingIdentifierKey]; } - (void)setEffectGroupingIdentifier:(NSString *)groupingIdentifier @@ -919,7 +958,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu [self _recalcActiveAppearanceChain]; } -- (void)_recalcActiveAppearanceChain +- (void)_recalcActiveAppearanceChain API_AVAILABLE(ios(13.0)) { NSMutableArray* chain = [NSMutableArray new]; @@ -954,10 +993,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu { _popupItem = popupItem; - if (@available(iOS 13.0, *)) - { - [self _recalcActiveAppearanceChain]; - } + [self _recalcActiveAppearanceChain]; } - (void)popupBarAppearanceDidChange:(LNPopupBarAppearance*)popupBarAppearance API_AVAILABLE(ios(13.0)) @@ -967,28 +1003,31 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu - (void)_appearanceDidChange { - _LNPopupBarAppearanceLegacySupport* legacySupport; - if (@available(iOS 13.0, *)) { - legacySupport = (id)self.activeAppearance; - } else { - legacySupport = [_LNPopupBarAppearanceLegacySupport new]; + _LNPopupBarAppearanceLegacySupport* activeAppearance; + if(@available(iOS 13.0, *)) + { + activeAppearance = (id)self.activeAppearance; + } + else + { + activeAppearance = [_LNPopupBarAppearanceLegacySupport new]; } - _highlightView.backgroundColor = legacySupport.highlightColor; + _highlightView.backgroundColor = activeAppearance.highlightColor; BOOL isFloating = _resolvedStyle == LNPopupBarStyleFloating; if(isFloating) { - id effect = [legacySupport floatingBackgroundEffectForTraitCollection:self.traitCollection]; + id effect = [activeAppearance floatingBackgroundEffectForTraitCollection:self.traitCollection]; _contentView.effect = effect; - __auto_type floatingBackgroundColor = legacySupport.floatingBackgroundColor; - __auto_type floatingBackgroundImage = legacySupport.floatingBackgroundImage; + __auto_type floatingBackgroundColor = activeAppearance.floatingBackgroundColor; + __auto_type floatingBackgroundImage = activeAppearance.floatingBackgroundImage; _contentView.foregroundColor = floatingBackgroundColor; _contentView.foregroundImage = floatingBackgroundImage; - _contentView.foregroundImageContentMode = legacySupport.floatingBackgroundImageContentMode; + _contentView.foregroundImageContentMode = activeAppearance.floatingBackgroundImageContentMode; [_contentView hideOrShowImageViewIfNecessary]; } else @@ -996,52 +1035,29 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _contentView.effect = nil; _contentView.foregroundColor = nil; _contentView.foregroundImage = nil; - _contentView.foregroundImageContentMode = 0; + _contentView.foregroundImageContentMode = (UIViewContentMode)0; [_contentView hideOrShowImageViewIfNecessary]; } - __auto_type backgroundColor = legacySupport.backgroundColor; - __auto_type backgroundImage = legacySupport.backgroundImage; + __auto_type backgroundColor = activeAppearance.backgroundColor; + __auto_type backgroundImage = activeAppearance.backgroundImage; + _backgroundView.effect = activeAppearance.backgroundEffect; + _backgroundView.foregroundColor = backgroundColor; + _backgroundView.foregroundImage = backgroundImage; + _backgroundView.foregroundImageContentMode = activeAppearance.backgroundImageContentMode; + [_backgroundView hideOrShowImageViewIfNecessary]; if(@available(iOS 13.0, *)) { - _backgroundView.effect = legacySupport.backgroundEffect; - } - else - { - if([_barContainingController isKindOfClass:UINavigationController.class]) - { - UIToolbar* toolbar = [_barContainingController toolbar]; - if(toolbar.barStyle == UIBarStyleBlack) - { - _backgroundView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; - } - else - { - _backgroundView.effect = legacySupport.backgroundEffect; - } - } - else - { - _backgroundView.effect = legacySupport.backgroundEffect; - } - } - _backgroundView.foregroundColor = backgroundColor; - _backgroundView.foregroundImage = backgroundImage; - _backgroundView.foregroundImageContentMode = legacySupport.backgroundImageContentMode; - [_backgroundView hideOrShowImageViewIfNecessary]; - - if (@available(iOS 13.0, *)) - { - _toolbar.standardAppearance.buttonAppearance = legacySupport.buttonAppearance ?: _toolbar.standardAppearance.buttonAppearance; - _toolbar.standardAppearance.doneButtonAppearance = legacySupport.doneButtonAppearance ?: _toolbar.standardAppearance.doneButtonAppearance; + _toolbar.standardAppearance.buttonAppearance = activeAppearance.buttonAppearance ?: _toolbar.standardAppearance.buttonAppearance; + _toolbar.standardAppearance.doneButtonAppearance = activeAppearance.doneButtonAppearance ?: _toolbar.standardAppearance.doneButtonAppearance; } - _shadowView.image = legacySupport.shadowImage; - _shadowView.backgroundColor = legacySupport.shadowColor; - _bottomShadowView.image = legacySupport.shadowImage; - _bottomShadowView.backgroundColor = legacySupport.shadowColor; + _shadowView.image = activeAppearance.shadowImage; + _shadowView.backgroundColor = activeAppearance.shadowColor; + _bottomShadowView.image = activeAppearance.shadowImage; + _bottomShadowView.backgroundColor = activeAppearance.shadowColor; _shadowView.hidden = _resolvedStyle == LNPopupBarStyleFloating ? YES : NO; if(_resolvedStyle == LNPopupBarStyleFloating) @@ -1049,13 +1065,13 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _bottomShadowView.hidden = YES; } - _floatingBackgroundShadowView.shadow = legacySupport.floatingBarBackgroundShadow; + _floatingBackgroundShadowView.shadow = activeAppearance.floatingBarBackgroundShadow; - _imageView.shadow = legacySupport.imageShadow; + _imageView.shadow = activeAppearance.imageShadow; - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { - [self.customBarViewController _activeAppearanceDidChange:(id)legacySupport]; + [self.customBarViewController _activeAppearanceDidChange:(id)activeAppearance]; } //Recalculate labels @@ -1121,11 +1137,14 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu if(_swiftuiImageController != nil) { [_swiftuiImageController.view removeFromSuperview]; + [_swiftuiImageController removeObserver:self forKeyPath:@"preferredContentSize"]; } _swiftuiImageController = swiftuiImageController; if(_swiftuiImageController != nil) { + [_swiftuiImageController addObserver:self forKeyPath:@"preferredContentSize" options:NSKeyValueObservingOptionNew context:NULL]; + _swiftuiImageController.view.backgroundColor = UIColor.clearColor; _swiftuiImageController.view.translatesAutoresizingMaskIntoConstraints = NO; @@ -1150,8 +1169,13 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu } _swiftuiTitleContentView = swiftuiTitleContentView; - _swiftuiTitleContentView.backgroundColor = UIColor.clearColor; - _swiftuiTitleContentView.translatesAutoresizingMaskIntoConstraints = NO; + + if(_swiftuiTitleContentView != nil) + { + [_swiftuiTitleContentView _ln_freezeInsets]; + _swiftuiTitleContentView.backgroundColor = UIColor.clearColor; + _swiftuiTitleContentView.translatesAutoresizingMaskIntoConstraints = NO; + } [self _setNeedsTitleLayoutRemovingLabels:YES]; } @@ -1188,11 +1212,18 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _swiftHacksWindow1.hidden = YES; _swiftHacksWindow1 = nil; } - _swiftHacksWindow1 = [[UIWindow alloc] initWithWindowScene:self.window.windowScene]; - _swiftHacksWindow1.frame = CGRectMake(-4000, 0, 400, 400); - _swiftHacksWindow1.rootViewController = _swiftuiHiddenLeadingController; - _swiftHacksWindow1.hidden = NO; - _swiftHacksWindow1.alpha = 0.0; + + if(_swiftuiHiddenLeadingController != nil) + { + [UIView performWithoutAnimation:^{ + _swiftHacksWindow1 = [[UIWindow alloc] initWithWindowScene:self.window.windowScene]; + _swiftHacksWindow1.frame = CGRectMake(-4000, 0, 400, 400); + _swiftHacksWindow1.rootViewController = _swiftuiHiddenLeadingController; + _swiftHacksWindow1.hidden = NO; + _swiftHacksWindow1.alpha = 0.0; + [_swiftHacksWindow1 layoutSubviews]; + }]; + } [self _fixupSwiftUIControllersWithBarStyle]; } @@ -1217,11 +1248,18 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _swiftHacksWindow2.hidden = YES; _swiftHacksWindow2 = nil; } - _swiftHacksWindow2 = [[UIWindow alloc] initWithWindowScene:self.window.windowScene]; - _swiftHacksWindow2.frame = CGRectMake(-4000, 0, 400, 400); - _swiftHacksWindow2.rootViewController = _swiftuiHiddenTrailingController; - _swiftHacksWindow2.hidden = NO; - _swiftHacksWindow2.alpha = 0.0; + + if(_swiftuiHiddenTrailingController != nil) + { + [UIView performWithoutAnimation:^{ + _swiftHacksWindow2 = [[UIWindow alloc] initWithWindowScene:self.window.windowScene]; + _swiftHacksWindow2.frame = CGRectMake(-4000, 0, 400, 400); + _swiftHacksWindow2.rootViewController = _swiftuiHiddenTrailingController; + _swiftHacksWindow2.hidden = NO; + _swiftHacksWindow2.alpha = 0.0; + [_swiftHacksWindow2 layoutSubviews]; + }]; + } [self _fixupSwiftUIControllersWithBarStyle]; } @@ -1278,30 +1316,30 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu [self setNeedsLayout]; } -- (UILabel<__MarqueeLabelType>*)_labelWithMarqueeEnabled:(BOOL)marqueeEnabled +- (UILabel*)_labelWithMarqueeEnabled:(BOOL)marqueeEnabled { - UILabel<__MarqueeLabelType>* _rv = nil; + UILabel* _rv = nil; if(!marqueeEnabled) { - __FakeMarqueeLabel* rv = [__FakeMarqueeLabel new]; + LNNonMarqueeLabel* rv = [LNNonMarqueeLabel new]; rv.minimumScaleFactor = 1.0; rv.lineBreakMode = NSLineBreakByTruncatingTail; _rv = rv; } else { - _LNPopupBarAppearanceLegacySupport* legacySupport; - if (@available(iOS 13.0, *)) { - legacySupport = (id)self.activeAppearance; + _LNPopupBarAppearanceLegacySupport* activeAppearance; + if(@available(iOS 13.0, *)) { + activeAppearance = (id)self.activeAppearance; } else { - legacySupport = [_LNPopupBarAppearanceLegacySupport new]; + activeAppearance = [_LNPopupBarAppearanceLegacySupport new]; } - MarqueeLabel* rv = [[MarqueeLabel alloc] initWithFrame:CGRectZero rate:legacySupport.marqueeScrollRate andFadeLength:10]; + MarqueeLabel* rv = [[MarqueeLabel alloc] initWithFrame:CGRectZero rate:activeAppearance.marqueeScrollRate andFadeLength:10]; rv.leadingBuffer = 0.0; rv.trailingBuffer = 20.0; - rv.animationDelay = legacySupport.marqueeScrollDelay; + rv.animationDelay = activeAppearance.marqueeScrollDelay; rv.marqueeType = MLContinuous; rv.holdScrolling = YES; _rv = rv; @@ -1317,8 +1355,10 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu - (UIView*)_viewForBarButtonItem:(UIBarButtonItem*)barButtonItem { UIView* itemView = [barButtonItem valueForKey:@"view"]; - //_UITAMICAdaptorView - if([itemView.superview isKindOfClass:NSClassFromString(_LNPopupDecodeBase64String(@"X1VJVEFNSUNBZGFwdG9yVmlldw=="))]) + + static NSString* adaptorView = LNPopupHiddenString("_UITAMICAdaptorView"); + + if([itemView.superview isKindOfClass:NSClassFromString(adaptorView)]) { itemView = itemView.superview; } @@ -1401,22 +1441,27 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu - (void)_updateTitleInsetsForProminentBar:(UIEdgeInsets*)titleInsets { - UIUserInterfaceLayoutDirection layoutDirection = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute]; + BOOL isRTL = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft; UIView* leftViewLast; UIView* rightViewFirst; NSArray* allItems = _toolbar.items; - if(layoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) + static Class systemBarButtonItemButtonClass = NSClassFromString(LNPopupHiddenString("_UIButtonBarButton")); + BOOL isTrailingSystem; + + if(isRTL == NO) { [self _getLeftmostView:&rightViewFirst rightmostView:NULL fromBarButtonItems:allItems]; leftViewLast = _imageView.hidden ? nil : _imageView; + isTrailingSystem = [rightViewFirst isKindOfClass:systemBarButtonItemButtonClass]; } else { [self _getLeftmostView:NULL rightmostView:&leftViewLast fromBarButtonItems:allItems]; rightViewFirst = _imageView.hidden ? nil : _imageView; + isTrailingSystem = [leftViewLast isKindOfClass:systemBarButtonItemButtonClass]; } #if DEBUG @@ -1444,7 +1489,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu } else { - leftViewLastFrame.size.width -= (__applySwiftUILayoutFixes ? -8 : 8); + leftViewLastFrame.size.width -= (__applySwiftUILayoutFixes ? -8 : isTrailingSystem ? 8 : 0); } } else @@ -1463,7 +1508,7 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu } else { - rightViewFirstFrame.origin.x += (__applySwiftUILayoutFixes ? -8 : 8); + rightViewFirstFrame.origin.x += (__applySwiftUILayoutFixes ? -8 : isTrailingSystem ? 8 : 0); } } else @@ -1527,9 +1572,12 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu //DO NOT CHANGE NAME! Used by LNPopupUI - (UIColor*)_titleColor { - if (@available(iOS 13.0, *)) { + if(@available(iOS 13.0, *)) + { return UIColor.labelColor; - } else { + } + else + { if([_barContainingController isKindOfClass:UINavigationController.class]) { UIToolbar* toolbar = [_barContainingController toolbar]; @@ -1588,159 +1636,166 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu //DO NOT CHANGE NAME! Used by LNPopupUI - (UIColor*)_subtitleColor { - if (@available(iOS 13.0, *)) { + if(@available(iOS 13.0, *)) + { return UIColor.secondaryLabelColor; - } else { + } + else + { return UIColor.systemGrayColor; } } - (void)_layoutTitles { - _LNPopupBarAppearanceLegacySupport* legacySupport; - if (@available(iOS 13.0, *)) { - legacySupport = (id)self.activeAppearance; + _LNPopupBarAppearanceLegacySupport* activeAppearance; + if(@available(iOS 13.0, *)) { + activeAppearance = (id)self.activeAppearance; } else { - legacySupport = [_LNPopupBarAppearanceLegacySupport new]; + activeAppearance = [_LNPopupBarAppearanceLegacySupport new]; } - UIEdgeInsets titleInsets = UIEdgeInsetsZero; - - if(_resolvedStyle == LNPopupBarStyleCompact) - { - [self _updateTitleInsetsForCompactBar:&titleInsets]; - } - else - { - [self _updateTitleInsetsForProminentBar:&titleInsets]; - } - - if([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute] == UIUserInterfaceLayoutDirectionLeftToRight) - { - _titlesViewLeadingConstraint.constant = titleInsets.left; - _titlesViewTrailingConstraint.constant = titleInsets.right; - } - else - { - _titlesViewLeadingConstraint.constant = titleInsets.right; - _titlesViewTrailingConstraint.constant = titleInsets.left; - } - -#if DEBUG - if(_LNEnableBarLayoutDebug()) - { - _titlesView.backgroundColor = [UIColor.orangeColor colorWithAlphaComponent:0.6]; - } -#endif - - BOOL reset = NO; - - if(_needsLabelsLayout == YES) - { - if(_swiftuiTitleContentView != nil) + void (^layoutTitles)(void) = ^{ + UIEdgeInsets titleInsets = UIEdgeInsetsZero; + + if(_resolvedStyle == LNPopupBarStyleCompact) { - [_titlesView addArrangedSubview:_swiftuiTitleContentView]; - [_titlesView layoutIfNeeded]; - UIView* textView = _swiftuiTitleContentView.subviews.firstObject; - [NSLayoutConstraint activateConstraints:@[ - [_swiftuiTitleContentView.heightAnchor constraintEqualToAnchor:textView.heightAnchor], - ]]; + [self _updateTitleInsetsForCompactBar:&titleInsets]; } else { - if(_titleLabel == nil) - { - _titleLabel = [self _labelWithMarqueeEnabled:legacySupport.marqueeScrollEnabled]; -#if DEBUG - if(_LNEnableBarLayoutDebug()) - { - _titleLabel.backgroundColor = [UIColor.redColor colorWithAlphaComponent:0.5]; - } -#endif - _titleLabel.textColor = self._titleColor; - _titleLabel.font = self._titleFont; - if(_resolvedStyle == LNPopupBarStyleCompact) - { - _titleLabel.textAlignment = NSTextAlignmentCenter; - } - - [_titlesView addArrangedSubview:_titleLabel]; - } - - NSAttributedString* attr = _attributedTitle.length > 0 ? [NSAttributedString ln_attributedStringWithAttributedString:_attributedTitle defaultAttributes:legacySupport.titleTextAttributes] : nil; - if(attr != nil && [_titleLabel.attributedText isEqualToAttributedString:attr] == NO) - { - _titleLabel.attributedText = attr; - reset = YES; - } - - if(_subtitleLabel == nil) - { - _subtitleLabel = [self _labelWithMarqueeEnabled:legacySupport.marqueeScrollEnabled]; -#if DEBUG - if(_LNEnableBarLayoutDebug()) - { - _subtitleLabel.backgroundColor = [UIColor.cyanColor colorWithAlphaComponent:0.5]; - } -#endif - _subtitleLabel.textColor = self._subtitleColor; - _subtitleLabel.font = self._subtitleFont; - if(_resolvedStyle == LNPopupBarStyleCompact) - { - _subtitleLabel.textAlignment = NSTextAlignmentCenter; - } - - [_titlesView addArrangedSubview:_subtitleLabel]; - } - - attr = _attributedSubtitle.length > 0 ? [NSAttributedString ln_attributedStringWithAttributedString:_attributedSubtitle defaultAttributes:legacySupport.subtitleTextAttributes] : nil; - if(attr != nil && [_subtitleLabel.attributedText isEqualToAttributedString:attr] == NO) - { - _subtitleLabel.attributedText = attr; - reset = YES; - } + [self _updateTitleInsetsForProminentBar:&titleInsets]; } - if(reset) + if(self.effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) { - [_titleLabel resetLabel]; - [_subtitleLabel resetLabel]; - } - - if(_attributedSubtitle.length > 0) - { - _subtitleLabel.hidden = NO; - - if(_needsLabelsLayout == YES) - { - if([_subtitleLabel isPaused] && [_titleLabel isPaused] == NO) - { - [_subtitleLabel unpauseLabel]; - } - } + _titlesViewLeadingConstraint.constant = titleInsets.left; + _titlesViewTrailingConstraint.constant = titleInsets.right; } else { - _subtitleLabel.hidden = YES; - - if(_needsLabelsLayout == YES) + _titlesViewLeadingConstraint.constant = titleInsets.right; + _titlesViewTrailingConstraint.constant = titleInsets.left; + } + +#if DEBUG + if(_LNEnableBarLayoutDebug()) + { + _titlesView.backgroundColor = [UIColor.orangeColor colorWithAlphaComponent:0.6]; + } +#endif + + BOOL reset = NO; + + if(_needsLabelsLayout == YES) + { + if(_swiftuiTitleContentView != nil) { + [_titleLabel.superview removeFromSuperview]; + _titleLabel = nil; + [_subtitleLabel.superview removeFromSuperview]; + _subtitleLabel = nil; + + [_titlesView addArrangedSubview:_swiftuiTitleContentView]; + [_titlesView layoutIfNeeded]; + if(unavailable(iOS 17.0, *)) { + UIView* textView = _swiftuiTitleContentView.subviews.firstObject; + [NSLayoutConstraint activateConstraints:@[ + [_swiftuiTitleContentView.heightAnchor constraintEqualToAnchor:textView.heightAnchor], + ]]; + } + } + else + { + if(_titleLabel == nil) + { + _titleLabel = [self _labelWithMarqueeEnabled:activeAppearance.marqueeScrollEnabled]; +#if DEBUG + if(_LNEnableBarLayoutDebug()) + { + _titleLabel.backgroundColor = [UIColor.redColor colorWithAlphaComponent:0.5]; + } +#endif + _titleLabel.textColor = self._titleColor; + _titleLabel.font = self._titleFont; + if(_resolvedStyle == LNPopupBarStyleCompact) + { + _titleLabel.textAlignment = NSTextAlignmentCenter; + } + + [_titlesView addArrangedSubview:[_LNPopupTitleLabelWrapper wrapperForLabel:_titleLabel]]; + } + + NSAttributedString* attr = _attributedTitle.length > 0 ? [NSAttributedString ln_attributedStringWithAttributedString:_attributedTitle defaultAttributes:activeAppearance.titleTextAttributes] : nil; + if(attr != nil && [_titleLabel.attributedText isEqualToAttributedString:attr] == NO) + { + _titleLabel.attributedText = attr; + reset = YES; + } + + if(_subtitleLabel == nil) + { + _subtitleLabel = [self _labelWithMarqueeEnabled:activeAppearance.marqueeScrollEnabled]; +#if DEBUG + if(_LNEnableBarLayoutDebug()) + { + _subtitleLabel.backgroundColor = [UIColor.cyanColor colorWithAlphaComponent:0.5]; + } +#endif + _subtitleLabel.textColor = self._subtitleColor; + _subtitleLabel.font = self._subtitleFont; + if(_resolvedStyle == LNPopupBarStyleCompact) + { + _subtitleLabel.textAlignment = NSTextAlignmentCenter; + } + + [_titlesView addArrangedSubview:[_LNPopupTitleLabelWrapper wrapperForLabel:_subtitleLabel]]; + } + + attr = _attributedSubtitle.length > 0 ? [NSAttributedString ln_attributedStringWithAttributedString:_attributedSubtitle defaultAttributes:activeAppearance.subtitleTextAttributes] : nil; + if(attr != nil && [_subtitleLabel.attributedText isEqualToAttributedString:attr] == NO) + { + _subtitleLabel.attributedText = attr; + reset = YES; + } + } + + if(reset) + { + [_titleLabel resetLabel]; [_subtitleLabel resetLabel]; - [_subtitleLabel pauseLabel]; + } + + if(_attributedSubtitle.length > 0) + { + _subtitleLabel.hidden = NO; + + if(_needsLabelsLayout == YES) + { + if([_subtitleLabel isPaused] && [_titleLabel isPaused] == NO) + { + [_subtitleLabel unpauseLabel]; + } + } + } + else + { + _subtitleLabel.hidden = YES; + + if(_needsLabelsLayout == YES) + { + [_subtitleLabel resetLabel]; + [_subtitleLabel pauseLabel]; + } } } - } - [self _updateAccessibility]; + [self _updateAccessibility]; + + [self _recalculateCoordinatedMarqueeScrollIfNeeded]; + }; - [self _recalculateCoordinatedMarqueeScrollIfNeeded]; - - [UIView performWithoutAnimation:^{ - [_titleLabel layoutIfNeeded]; - [_subtitleLabel layoutIfNeeded]; - [_titlesView layoutIfNeeded]; - [_contentView layoutIfNeeded]; - }]; + layoutTitles(); _needsLabelsLayout = NO; } @@ -1788,16 +1843,56 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu _titleLabel = nil; _subtitleLabel = nil; - [l1 removeFromSuperview]; - [l2 removeFromSuperview]; + [l1.superview removeFromSuperview]; + [l2.superview removeFromSuperview]; } [self setNeedsLayout]; } +static CGSize LNMakeSizeWithAspectRatioInsideSize(CGSize aspectRatio, CGSize size) +{ + CGFloat outerAspectRatio = size.width / size.height; + CGFloat fAspectRatio = aspectRatio.width / aspectRatio.height; + + if(fAspectRatio < outerAspectRatio) + { + return CGSizeMake(size.height * fAspectRatio, size.height); + } + else if(fAspectRatio > outerAspectRatio) + { + return CGSizeMake(size.width, size.width / fAspectRatio); + } + else + { + return size; + } +} + +- (CGSize)_imageViewSizeWithMaxWidth:(CGFloat)width maxHeight:(CGFloat)height +{ + if(_imageView.image == nil && _swiftuiImageController == nil) + { + return CGSizeMake(width, height); + } + + if(_swiftuiImageController != nil) + { + return LNMakeSizeWithAspectRatioInsideSize(_swiftuiImageController.preferredContentSize, CGSizeMake(width, height)); + } + + if(_imageView.contentMode != UIViewContentModeScaleAspectFit) + { + return CGSizeMake(width, height); + } + + return LNMakeSizeWithAspectRatioInsideSize(_imageView.image.size, CGSizeMake(width, height)); +} + - (void)_layoutImageView { BOOL previouslyHidden = _imageView.hidden; + CGSize previousSize = _imageView.bounds.size; if(_resolvedStyle == LNPopupBarStyleCompact) { @@ -1812,22 +1907,31 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu UIUserInterfaceLayoutDirection layoutDirection = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute]; BOOL isFloating = _resolvedStyle == LNPopupBarStyleFloating; - CGFloat imageSize = isFloating ? LNPopupBarFloatingImageWidth : LNPopupBarProminentImageWidth; + CGFloat maxImageDimention = isFloating ? LNPopupBarFloatingImageWidth : LNPopupBarProminentImageWidth; CGFloat barHeight = _contentView.bounds.size.height; CGFloat safeLeading = 8; + + if(_resolvedStyle == LNPopupBarStyleFloating && self.isWidePad == YES) + { + safeLeading += 2; + maxImageDimention = LNPopupBarFloatingPadImageWidth; + } + + CGSize imageViewSize = [self _imageViewSizeWithMaxWidth:maxImageDimention maxHeight:maxImageDimention]; + if(layoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) { - _imageView.center = CGPointMake(safeLeading + imageSize / 2, barHeight / 2); + _imageView.center = CGPointMake(safeLeading + imageViewSize.width / 2, barHeight / 2); } else { - _imageView.center = CGPointMake(_contentView.bounds.size.width - safeLeading - imageSize / 2, barHeight / 2); + _imageView.center = CGPointMake(_contentView.bounds.size.width - safeLeading - imageViewSize.width / 2, barHeight / 2); } - _imageView.bounds = CGRectMake(0, 0, imageSize, imageSize); + _imageView.bounds = (CGRect){0, 0, imageViewSize}; - if(previouslyHidden != _imageView.hidden) + if(previouslyHidden != _imageView.hidden || CGSizeEqualToSize(previousSize, imageViewSize) == NO) { [self _setNeedsTitleLayoutRemovingLabels:NO]; } @@ -1909,6 +2013,12 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu { [self._barDelegate _popupBarMetricsDidChange:self]; } + + if([keyPath isEqualToString:@"preferredContentSize"] == YES && object == _swiftuiImageController) + { + [self _layoutImageView]; + [self _setNeedsTitleLayoutRemovingLabels:NO]; + } } - (void)setCustomBarViewController:(LNPopupCustomBarViewController*)customBarViewController @@ -1944,12 +2054,12 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu [self._barDelegate _popupBar:self updateCustomBarController:_customBarViewController cleanup:NO]; [_customBarViewController addObserver:self forKeyPath:@"preferredContentSize" options:NSKeyValueObservingOptionNew context:NULL]; - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { [_customBarViewController _activeAppearanceDidChange:self.activeAppearance]; } - [self.contentView addSubview:_customBarViewController.view]; + [_contentView.contentView insertSubview:_customBarViewController.view aboveSubview:_bottomShadowView]; if(_customBarViewController.view.translatesAutoresizingMaskIntoConstraints == NO) { @@ -1989,14 +2099,17 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu - (void)_recalculateCoordinatedMarqueeScrollIfNeeded { - _LNPopupBarAppearanceLegacySupport* legacySupport; - if (@available(iOS 13.0, *)) { - legacySupport = (id)self.activeAppearance; - } else { - legacySupport = [_LNPopupBarAppearanceLegacySupport new]; + _LNPopupBarAppearanceLegacySupport* activeAppearance; + if(@available(iOS 13.0, *)) + { + activeAppearance = (id)self.activeAppearance; + } + else + { + activeAppearance = [_LNPopupBarAppearanceLegacySupport new]; } - if(legacySupport.marqueeScrollEnabled == NO) + if(activeAppearance.marqueeScrollEnabled == NO) { return; } @@ -2009,10 +2122,10 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu MarqueeLabel* titleLabel = (id)_titleLabel; MarqueeLabel* subtitleLabel = (id)_subtitleLabel; - titleLabel.animationDelay = legacySupport.marqueeScrollDelay; - subtitleLabel.animationDelay = legacySupport.marqueeScrollDelay; + titleLabel.animationDelay = activeAppearance.marqueeScrollDelay; + subtitleLabel.animationDelay = activeAppearance.marqueeScrollDelay; - if(legacySupport.coordinateMarqueeScroll == YES && _attributedTitle.length > 0 && _attributedSubtitle.length > 0) + if(activeAppearance.coordinateMarqueeScroll == YES && _attributedTitle.length > 0 && _attributedSubtitle.length > 0) { titleLabel.holdScrolling = YES; subtitleLabel.holdScrolling = YES; @@ -2089,6 +2202,41 @@ static inline __attribute__((always_inline)) LNPopupBarProgressViewStyle _LNPopu } } ++ (BOOL)isCatalystApp +{ + if(@available(iOS 13.0, *)) + { + BOOL isCatalystApp = NSProcessInfo.processInfo.isMacCatalystApp; + if(@available(iOS 14.0, *)) + { + isCatalystApp = isCatalystApp || NSProcessInfo.processInfo.iOSAppOnMac; + } + + return isCatalystApp; + } + else + { + return NO; + } +} + +- (BOOL)isWidePad +{ + if(LNPopupBar.isCatalystApp) + { + return YES; + } + + return self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular && UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad; +} + +- (void)setLimitFloatingContentWidth:(BOOL)limitFloatingContentWidth +{ + _limitFloatingContentWidth = limitFloatingContentWidth; + + [self setNeedsLayout]; +} + #pragma mark UIPointerInteractionDelegate - (nullable UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)) diff --git a/LNPopupController/LNPopupController/Private/LNPopupBarAppearance+Private.h b/LNPopupController/LNPopupController/Private/LNPopupBarAppearance+Private.h index 5c3e2d1..d6327a4 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupBarAppearance+Private.h +++ b/LNPopupController/LNPopupController/Private/LNPopupBarAppearance+Private.h @@ -2,21 +2,19 @@ // LNPopupBarAppearance+Private.h // LNPopupController // -// Created by Leo Natan on 6/9/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-06-20. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN -API_AVAILABLE(ios(13.0)) @interface _LNPopupDominantColorTrait : NSObject @end -API_AVAILABLE(ios(13.0)) @protocol _LNPopupBarAppearanceDelegate -- (void)popupBarAppearanceDidChange:(LNPopupBarAppearance*)popupBarAppearance; +- (void)popupBarAppearanceDidChange:(LNPopupBarAppearance*)popupBarAppearance API_AVAILABLE(ios(13.0)); @end diff --git a/LNPopupController/LNPopupController/Private/LNPopupBarAppearance.m b/LNPopupController/LNPopupController/Private/LNPopupBarAppearance.mm similarity index 91% rename from LNPopupController/LNPopupController/Private/LNPopupBarAppearance.m rename to LNPopupController/LNPopupController/Private/LNPopupBarAppearance.mm index 9094348..9acc94b 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupBarAppearance.m +++ b/LNPopupController/LNPopupController/Private/LNPopupBarAppearance.mm @@ -2,20 +2,16 @@ // LNPopupBarAppearance.m // LNPopupController // -// Created by Leo Natan on 6/9/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-06-20. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupBarAppearance+Private.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" static void* _LNPopupItemObservationContext = &_LNPopupItemObservationContext; -//appearance:categoriesChanged: -static NSString* const aCC = @"YXBwZWFyYW5jZTpjYXRlZ29yaWVzQ2hhbmdlZDo="; -//changeObserver -static NSString* const cO = @"Y2hhbmdlT2JzZXJ2ZXI="; - @implementation LNPopupBarAppearance { BOOL _wantsDynamicFloatingBackgroundEffect; @@ -32,13 +28,12 @@ static NSArray* __notifiedProperties = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ __notifiedProperties = _LNPopupGetPropertyNames(self, nil); - }); - + #ifndef LNPopupControllerEnforceStrictClean - //appearance:categoriesChanged: - Method m1 = class_getInstanceMethod(self, @selector(a:cC:)); - class_addMethod(self, NSSelectorFromString(_LNPopupDecodeBase64String(aCC)), method_getImplementation(m1), method_getTypeEncoding(m1)); + Method m1 = class_getInstanceMethod(self, @selector(a:cC:)); + class_addMethod(self, NSSelectorFromString(LNPopupHiddenString("appearance:categoriesChanged:")), method_getImplementation(m1), method_getTypeEncoding(m1)); #endif + }); } } @@ -57,9 +52,10 @@ static NSArray* __notifiedProperties = nil; - (void)_commonInit { + static NSString* changeObserver = LNPopupHiddenString("changeObserver"); + #ifndef LNPopupControllerEnforceStrictClean - //changeObserver - [self setValue:self forKey:_LNPopupDecodeBase64String(cO)]; + [self setValue:self forKey:changeObserver]; #endif for(NSString* key in __notifiedProperties) @@ -70,10 +66,10 @@ static NSArray* __notifiedProperties = nil; - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - id old = change[NSKeyValueChangeOldKey]; - id new = change[NSKeyValueChangeNewKey]; + id oldValue = change[NSKeyValueChangeOldKey]; + id newValue = change[NSKeyValueChangeNewKey]; - if([old isEqual:new]) + if([oldValue isEqual:newValue]) { return; } @@ -181,7 +177,9 @@ static NSArray* __notifiedProperties = nil; for(NSString* key in __notifiedProperties) { - rv = rv && [[self valueForKey:key] isEqual:[other valueForKey:key]]; + id myVal = [self valueForKey:key]; + id otherVal = [other valueForKey:key]; + rv = rv && (myVal == otherVal || [myVal isEqual:otherVal]); } return rv; @@ -314,7 +312,7 @@ static NSArray* __notifiedProperties = nil; { return UIColor.clearColor; } - }];; + }]; self.floatingBackgroundImage = nil; self.floatingBackgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemChromeMaterial]; _wantsDynamicFloatingBackgroundEffect = YES; diff --git a/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.h b/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.h index ac04da7..a8dd1c7 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.h +++ b/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.h @@ -2,11 +2,11 @@ // LNPopupBarAppearanceChainProxy.h // LNPopupBarAppearanceChainProxy // -// Created by Leo Natan on 8/7/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-08-07. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // -@import UIKit; +#import #import "LNPopupBarAppearance+Private.h" NS_ASSUME_NONNULL_BEGIN @@ -14,9 +14,9 @@ NS_ASSUME_NONNULL_BEGIN API_AVAILABLE(ios(13.0)) @interface LNPopupBarAppearanceChainProxy : NSObject -@property (nonatomic, strong) NSArray* chain; +@property (nonatomic, strong) NSArray* chain API_AVAILABLE(ios(13.0)); -- (instancetype)initWithAppearanceChain:(NSArray*)chain; +- (instancetype)initWithAppearanceChain:(NSArray*)chain API_AVAILABLE(ios(13.0)); - (id)objectForKey:(NSString*)key; - (BOOL)boolForKey:(NSString*)key; - (NSUInteger)unsignedIntegerForKey:(NSString*)key; diff --git a/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.m b/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.m index 9530356..f6b79a5 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.m +++ b/LNPopupController/LNPopupController/Private/LNPopupBarAppearanceChainProxy.m @@ -2,8 +2,8 @@ // LNPopupBarAppearanceChainProxy.m // LNPopupBarAppearanceChainProxy // -// Created by Leo Natan on 8/7/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-08-07. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupBarAppearanceChainProxy.h" diff --git a/LNPopupController/LNPopupController/Private/LNPopupCloseButton+Private.h b/LNPopupController/LNPopupController/Private/LNPopupCloseButton+Private.h index e26a9eb..4177d19 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupCloseButton+Private.h +++ b/LNPopupController/LNPopupController/Private/LNPopupCloseButton+Private.h @@ -2,8 +2,8 @@ // LNPopupCloseButton+Private.h // LNPopupController // -// Created by Leo Natan on 13/11/2016. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2016-12-02. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNPopupCloseButton.m b/LNPopupController/LNPopupController/Private/LNPopupCloseButton.mm similarity index 85% rename from LNPopupController/LNPopupController/Private/LNPopupCloseButton.m rename to LNPopupController/LNPopupController/Private/LNPopupCloseButton.mm index 43241dc..163e072 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupCloseButton.m +++ b/LNPopupController/LNPopupController/Private/LNPopupCloseButton.mm @@ -2,14 +2,14 @@ // LNPopupCloseButton.m // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupCloseButton+Private.h" -@import ObjectiveC; +#import #import "LNChevronView.h" -#import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" #import "LNPopupContentView+Private.h" @interface LNPopupCloseButton () @@ -23,6 +23,8 @@ @end +@interface LNPopupCloseButton () @end + __attribute__((objc_direct_members)) @implementation LNPopupCloseButton { @@ -36,15 +38,12 @@ __attribute__((objc_direct_members)) #ifndef LNPopupControllerEnforceStrictClean -//_actingParentViewForGestureRecognizers -static NSString* const _aPVFGR = @"X2FjdGluZ1BhcmVudFZpZXdGb3JHZXN0dXJlUmVjb2duaXplcnM="; - + (void)load { @autoreleasepool { Method m = class_getInstanceMethod(self, @selector(_aPVFGR)); - class_addMethod(self, NSSelectorFromString(_LNPopupDecodeBase64String(_aPVFGR)), method_getImplementation(m), method_getTypeEncoding(m)); + class_addMethod(self, NSSelectorFromString(LNPopupHiddenString("_actingParentViewForGestureRecognizers")), method_getImplementation(m), method_getTypeEncoding(m)); } } @@ -72,29 +71,29 @@ static NSString* const _aPVFGR = @"X2FjdGluZ1BhcmVudFZpZXdGb3JHZXN0dXJlUmVjb2dua [self setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; [self setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; - if (@available(iOS 13.4, *)) - { - self.pointerInteractionEnabled = YES; - self.pointerStyleProvider = ^ UIPointerStyle* (UIButton *button, UIPointerEffect *proposedEffect, UIPointerShape *proposedShape) { - NSValue* rectValue = [proposedShape valueForKey:@"rect"]; - if(rectValue == nil) - { - return [UIPointerStyle styleWithEffect:proposedEffect shape:proposedShape]; - } - - CGRect rect = CGRectInset(rectValue.CGRectValue, -5, -5); - - return [UIPointerStyle styleWithEffect:proposedEffect shape:[UIPointerShape shapeWithRoundedRect:rect]]; - }; - } - _style = LNPopupCloseButtonStyleGrabber; [self _setupForChevronButton]; + + if(@available(iOS 13.4, *)) + { + self.pointerInteractionEnabled = YES; + self.pointerStyleProvider = ^UIPointerStyle * _Nullable(UIButton * _Nonnull button, UIPointerEffect * _Nonnull proposedEffect, UIPointerShape * _Nonnull proposedShape) { + UIPointerLiftEffect* effect = [UIPointerLiftEffect effectWithPreview:[[UITargetedPreview alloc] initWithView:self]]; + UIPointerShape* shape = nil;//[UIPointerShape shapeWithRoundedRect:interaction.view.frame]; + + return [UIPointerStyle styleWithEffect:effect shape:shape]; + }; + } } return self; } +- (LNPopupCloseButtonStyle)effectiveStyle +{ + return self.popupContentView.effectivePopupCloseButtonStyle; +} + - (void)setStyle:(LNPopupCloseButtonStyle)style { //This will take care of cases where the user sets LNPopupCloseButtonStyleDefault as well as close button repositioning. @@ -171,14 +170,13 @@ static NSString* const _aPVFGR = @"X2FjdGluZ1BhcmVudFZpZXdGb3JHZXN0dXJlUmVjb2dua - (void)_setupForCircularButton { UIBlurEffectStyle blurStyle; - - if (@available(iOS 13.0, *)) - { + if(@available(iOS 13.0, *)) { blurStyle = UIBlurEffectStyleSystemChromeMaterial; - } else { + } + else + { blurStyle = UIBlurEffectStyleExtraLight; } - _effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:blurStyle]]; _effectView.userInteractionEnabled = NO; [self addSubview:_effectView]; @@ -206,16 +204,20 @@ static NSString* const _aPVFGR = @"X2FjdGluZ1BhcmVudFZpZXdGb3JHZXN0dXJlUmVjb2dua self.layer.shadowOffset = CGSizeMake(0, 0); self.layer.masksToBounds = NO; - if (@available(iOS 13.0, *)) { - self.tintColor = [UIColor labelColor]; + if(@available(iOS 13.0, *)) + { + self.tintColor = UIColor.labelColor; + + [self setTitleColor:self.tintColor forState:UIControlStateNormal]; UIImageSymbolConfiguration* config = [UIImageSymbolConfiguration configurationWithPointSize:15 weight:UIImageSymbolWeightHeavy scale:UIImageSymbolScaleSmall]; UIImage* image = [[UIImage systemImageNamed:@"chevron.down" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [self setImage:image forState:UIControlStateNormal]; - } else { - self.tintColor = [UIColor darkTextColor]; } - [self setTitleColor:self.tintColor forState:UIControlStateNormal]; + else + { + self.tintColor = UIColor.darkTextColor; + } } - (void)_didTouchDown @@ -253,7 +255,7 @@ static NSString* const _aPVFGR = @"X2FjdGluZ1BhcmVudFZpZXdGb3JHZXN0dXJlUmVjb2dua }; if (animated) { - [UIView animateWithDuration:0.47 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ alphaBlock(); } completion:nil]; } else { diff --git a/LNPopupController/LNPopupController/Private/LNPopupContentView+Private.h b/LNPopupController/LNPopupController/Private/LNPopupContentView+Private.h index e0507f4..b941b1c 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupContentView+Private.h +++ b/LNPopupController/LNPopupController/Private/LNPopupContentView+Private.h @@ -2,8 +2,8 @@ // LNPopupContentView+Private.h // LNPopupController // -// Created by Leo Natan on 8/4/20. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2020-08-04. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNPopupContentView.m b/LNPopupController/LNPopupController/Private/LNPopupContentView.m index 3e7fc16..878676c 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupContentView.m +++ b/LNPopupController/LNPopupController/Private/LNPopupContentView.m @@ -2,8 +2,8 @@ // LNPopupContentView.m // LNPopupController // -// Created by Leo Natan on 8/4/20. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2020-08-04. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupController.h" @@ -16,11 +16,14 @@ LNPopupCloseButtonStyle _LNPopupResolveCloseButtonStyleFromCloseButtonStyle(LNPo LNPopupCloseButtonStyle rv = style; if(rv == LNPopupCloseButtonStyleDefault) { -#if TARGET_OS_MACCATALYST - rv = LNPopupCloseButtonStyleRound; -#else - rv = LNPopupCloseButtonStyleGrabber; -#endif + if([LNPopupBar isCatalystApp]) + { + rv = LNPopupCloseButtonStyleRound; + } + else + { + rv = LNPopupCloseButtonStyleGrabber; + } } return rv; } @@ -53,6 +56,32 @@ LNPopupCloseButtonStyle _LNPopupResolveCloseButtonStyleFromCloseButtonStyle(LNPo _popupCloseButton = [[LNPopupCloseButton alloc] initWithContainingContentView:self]; _popupCloseButton.popupContentView = self; + __weak __typeof(self) weakSelf = self; + if(@available(iOS 13.4, *)) + { + _popupCloseButton.pointerInteractionEnabled = YES; + _popupCloseButton.pointerStyleProvider = ^ UIPointerStyle* (UIButton *button, UIPointerEffect *proposedEffect, UIPointerShape *proposedShape) { + LNPopupCloseButtonStyle resolvedStyle = _LNPopupResolveCloseButtonStyleFromCloseButtonStyle(weakSelf.popupCloseButtonStyle); + + if(resolvedStyle == LNPopupCloseButtonStyleRound) + { + CGRect frame = CGRectInset(weakSelf.popupCloseButton.frame, 5, 5); + + return [UIPointerStyle styleWithEffect:proposedEffect shape:[UIPointerShape shapeWithPath:[UIBezierPath bezierPathWithOvalInRect:frame]]]; + } + + NSValue* rectValue = [proposedShape valueForKey:@"rect"]; + if(rectValue == nil) + { + return [UIPointerStyle styleWithEffect:proposedEffect shape:proposedShape]; + } + + CGRect rect = CGRectInset(rectValue.CGRectValue, -5, -5); + + return [UIPointerStyle styleWithEffect:proposedEffect shape:[UIPointerShape shapeWithRoundedRect:rect]]; + }; + } + [_popupCloseButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; [_popupCloseButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; [_popupCloseButton setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; @@ -193,6 +222,10 @@ LNPopupCloseButtonStyle _LNPopupResolveCloseButtonStyleFromCloseButtonStyle(LNPo topConstant += layoutFrame.origin.y; topConstant = MAX(self.popupCloseButton.style == LNPopupCloseButtonStyleRound ? 12 : 0, topConstant); +#if TARGET_OS_MACCATALYST + topConstant += 20; +#endif + CGFloat leadingConstant = layoutFrame.origin.x; if(topConstant != _popupCloseButtonTopConstraint.constant || leadingConstant != _popupCloseButtonLeadingConstraint.constant) diff --git a/LNPopupController/LNPopupController/Private/LNPopupController.h b/LNPopupController/LNPopupController/Private/LNPopupController.h index a87db41..09cd3cd 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupController.h +++ b/LNPopupController/LNPopupController/Private/LNPopupController.h @@ -2,8 +2,8 @@ // LNPopupController.h // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -11,10 +11,13 @@ #import "UIViewController+LNPopupSupportPrivate.h" #import #import "LNPopupContentView+Private.h" +#import "LNPopupBar+Private.h" -extern const NSUInteger _LNPopupPresentationStateTransitioning; +CF_EXTERN_C_BEGIN -@interface LNPopupController : NSObject +#define _LNPopupPresentationStateTransitioning ((LNPopupPresentationState)2) + +@interface LNPopupController : NSObject <_LNPopupBarDelegate> - (instancetype)initWithContainerViewController:(__kindof UIViewController*)containerController; @@ -22,6 +25,7 @@ extern const NSUInteger _LNPopupPresentationStateTransitioning; @property (nonatomic, strong) LNPopupBar* popupBar; @property (nonatomic, strong, readonly) LNPopupBar* popupBarStorage; +@property (nonatomic, strong, readonly) LNPopupBar* popupBarNoCreate; @property (nonatomic, strong) LNPopupContentView* popupContentView; @property (nonatomic, strong) UIScrollView* popupContentContainerView; @@ -59,4 +63,8 @@ extern const NSUInteger _LNPopupPresentationStateTransitioning; + (CGFloat)_statusBarHeightForView:(UIView*)view; +- (void)_fixupGestureRecognizer:(UIGestureRecognizer*)obj; + @end + +CF_EXTERN_C_END diff --git a/LNPopupController/LNPopupController/Private/LNPopupController.m b/LNPopupController/LNPopupController/Private/LNPopupController.mm similarity index 75% rename from LNPopupController/LNPopupController/Private/LNPopupController.m rename to LNPopupController/LNPopupController/Private/LNPopupController.mm index 7361b0d..27cc7ce 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupController.m +++ b/LNPopupController/LNPopupController/Private/LNPopupController.mm @@ -2,8 +2,8 @@ // LNPopupController.m // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupController.h" @@ -13,37 +13,62 @@ #import "LNPopupLongPressGestureRecognizer.h" #import "LNPopupInteractionPanGestureRecognizer.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" #import "UIView+LNPopupSupportPrivate.h" #import "LNPopupCustomBarViewController+Private.h" -@import ObjectiveC; -@import os.log; +#import "_LNPopupTransitionView.h" +#import "_LNPopupTransitionPreferredOpenAnimator.h" +#import "_LNPopupTransitionGenericOpenAnimator.h" +#import "_LNPopupTransitionGenericCloseAnimator.h" +#import "_LNPopupTransitionPreferredCloseAnimator.h" + +#import +#import + +#if TARGET_OS_MACCATALYST +#import +#endif + +#ifdef DEBUG +#import "LNPopupDebug.h" + +static BOOL _LNEnableSlowTransitionsDebug(void) +{ + return [__LNDebugUserDefaults() boolForKey:@"__LNPopupEnableSlowTransitionsDebug"]; +} +#endif + +CF_EXTERN_C_BEGIN #ifndef LNPopupControllerEnforceStrictClean //visualProvider.toolbarIsSmall static NSString* const _vPTIS = @"dmlzdWFsUHJvdmlkZXIudG9vbGJhcklzU21hbGw="; #endif -#if TARGET_OS_MACCATALYST -@import AppKit; -#endif - -const NSUInteger _LNPopupPresentationStateTransitioning = 2; - static const CGFloat LNPopupBarGestureHeightPercentThreshold = 0.2; -static const CGFloat LNPopupBarDeveloperPanGestureThreshold = 0; LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionStyle(LNPopupInteractionStyle style) { - LNPopupInteractionStyle rv = style; - if(rv == LNPopupInteractionStyleDefault) + if(@available(iOS 13.0, *)) { -#if TARGET_OS_MACCATALYST - rv = LNPopupInteractionStyleScroll; -#else - rv = LNPopupInteractionStyleSnap; -#endif + LNPopupInteractionStyle rv = style; + if(rv == LNPopupInteractionStyleDefault) + { + if([LNPopupBar isCatalystApp]) + { + rv = LNPopupInteractionStyleScroll; + } + else + { + rv = LNPopupInteractionStyleSnap; + } + } + return rv; + } + else + { + return LNPopupInteractionStyleSnap; } - return rv; } OS_ALWAYS_INLINE @@ -51,7 +76,7 @@ static BOOL _LNCallDelegateObjectObjectBool(UIViewController* controller, UIView { if([controller.popupPresentationDelegate respondsToSelector:selector]) { - void (*msgSendObjectObjectBool)(id, SEL, id, id, BOOL) = (void*)objc_msgSend; + void (*msgSendObjectObjectBool)(id, SEL, id, id, BOOL) = reinterpret_cast(objc_msgSend); msgSendObjectObjectBool(controller.popupPresentationDelegate, selector, controller, content, animated); return YES; } @@ -63,7 +88,7 @@ static BOOL _LNCallDelegateObjectBool(UIViewController* controller, SEL selector { if([controller.popupPresentationDelegate respondsToSelector:selector]) { - void (*msgSendObjectBool)(id, SEL, id, BOOL) = (void*)objc_msgSend; + void (*msgSendObjectBool)(id, SEL, id, BOOL) = reinterpret_cast(objc_msgSend); msgSendObjectBool(controller.popupPresentationDelegate, selector, controller, animated); return YES; } @@ -72,7 +97,7 @@ static BOOL _LNCallDelegateObjectBool(UIViewController* controller, SEL selector #pragma mark Popup Controller -@interface LNPopupController () <_LNPopupItemDelegate, _LNPopupBarDelegate> +@interface LNPopupController () <_LNPopupItemDelegate> - (void)_applicationDidEnterBackground; - (void)_applicationWillEnterForeground; @@ -175,28 +200,47 @@ __attribute__((objc_direct_members)) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; _wantsFeedbackGeneration = YES; - if (@available(iOS 13.0, *)) { + if(@available(iOS 13.0, *)) + { _softFeedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleSoft]; _rigidFeedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleRigid]; - } else { - // Fallback on earlier versions } } return self; } +- (void)setBottomBar:(UIView *)bottomBar +{ + if(@available(iOS 17.0, *)) + { + [_bottomBar.traitOverrides setObject:nil forTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } + + _bottomBar = bottomBar; + + if(LNPopupBar.isCatalystApp == YES) + { + return; + } + + if(@available(iOS 17.0, *)) + { + [_bottomBar.traitOverrides setObject:self.popupBar.effectGroupingIdentifier forTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } +} + - (CGRect)_frameForOpenPopupBar { -// CGRect defaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; return CGRectMake(0, - self.popupBar.frame.size.height, _containerController.view.bounds.size.width, self.popupBar.frame.size.height); } - (CGRect)_frameForClosedPopupBar { - CGRect defaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + CGRect defaultFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; UIEdgeInsets insets = [_containerController insetsForBottomDockingView]; - return CGRectMake(0, defaultFrame.origin.y - self.popupBar.frame.size.height - insets.bottom, _containerController.view.bounds.size.width, self.popupBar.frame.size.height); + CGFloat offset = [_containerController _ln_popupOffsetForPopupBarStyle:_popupBar.resolvedStyle]; + return CGRectMake(0, defaultFrame.origin.y - self.popupBar.frame.size.height - insets.bottom - offset, _containerController.view.bounds.size.width, self.popupBar.frame.size.height); } - (void)_repositionPopupContentMovingBottomBar:(BOOL)bottomBar animated:(BOOL)animated @@ -224,6 +268,13 @@ __attribute__((objc_direct_members)) CGFloat fractionalHeight = MAX(heightForContent - (self.popupBar.frame.origin.y + self.popupBar.frame.size.height), 0); contentFrame.size.height = ceil(fractionalHeight); + if(self.popupControllerTargetState <= LNPopupPresentationStateBarPresented) + { + CGFloat offset = [_containerController _ln_popupOffsetForPopupBarStyle:self.popupBar.effectiveBarStyle]; + contentFrame.size.height = 0; + contentFrame.origin.y -= offset; + } + self.popupContentView.frame = contentFrame; _containerController.popupContentViewController.view.frame = _containerController.view.bounds; @@ -265,10 +316,12 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) if(state == LNPopupPresentationStateOpen) { targetFrame = [self _frameForOpenPopupBar]; + self.popupContentView.popupCloseButton.alpha = 1.0; } else if(state == LNPopupPresentationStateBarPresented || (state == _LNPopupPresentationStateTransitioning && (_popupControllerTargetState == LNPopupPresentationStateBarHidden || _popupControllerTargetState == LNPopupPresentationStateBarPresented))) { targetFrame = [self _frameForClosedPopupBar]; + self.popupContentView.popupCloseButton.alpha = 0.0; } else { @@ -276,7 +329,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) targetFrame.size = closedFrame.size; } - _cachedDefaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + _cachedDefaultFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; _cachedInsets = [_containerController insetsForBottomDockingView]; self.popupBar.frame = targetFrame; @@ -284,6 +337,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) if(state != _LNPopupPresentationStateTransitioning) { [_containerController setNeedsStatusBarAppearanceUpdate]; + [_containerController setNeedsUpdateOfHomeIndicatorAutoHidden]; } [self _repositionPopupContentMovingBottomBar:_containerController._ignoringLayoutDuringTransition == NO animated:animated]; @@ -297,7 +351,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) } [currentContentController viewWillMoveToPopupContainerContentView:self.popupContentView]; - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { [self.popupContentView setControllerOverrideUserInterfaceStyle:currentContentController.overrideUserInterfaceStyle]; } @@ -329,8 +383,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) return; } - - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { [_softFeedbackGenerator prepare]; [_softFeedbackGenerator impactOccurredWithIntensity:intensity]; @@ -344,14 +397,99 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) return; } - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { [_rigidFeedbackGenerator prepare]; [_rigidFeedbackGenerator impactOccurredWithIntensity:intensity]; } } -- (void)_transitionToState:(LNPopupPresentationState)state notifyDelegate:(BOOL)notifyDelegate animated:(BOOL)animated useSpringAnimation:(BOOL)spring allowPopupBarAlphaModification:(BOOL)allowBarAlpha allowFeedbackGeneration:(BOOL)allowFeedbackGeneration completion:(void(^)(void))completion +- (BOOL)_validateViewForTransition:(UIView*)viewToValidate +{ + if(viewToValidate == nil) + { + return NO; + } + + if(viewToValidate == self.popupContentView || [viewToValidate isDescendantOfView:self.popupContentView] == NO) + { + return NO; + } + + return YES; +} + +- (_LNPopupTransitionView*)_userTransitionViewForTransitionFromState:(LNPopupPresentationState)fromState toState:(LNPopupPresentationState)state userView:(out id _Nonnull __strong * _Nonnull)userView +{ + _LNPopupTransitionView* userTransitionView = (id)[self.currentContentController _ln_transitionViewForPopupTransitionFromPresentationState:fromState toPresentationState:state view:userView]; + + if(userTransitionView == nil || [userTransitionView isKindOfClass:_LNPopupTransitionView.class] == NO) + { + return nil; + } + + if([self _validateViewForTransition:userTransitionView.sourceView] == NO) + { + return nil; + } + + return userTransitionView; +} + +- (UIView*)_supportedUserViewForTransitionFromState:(LNPopupPresentationState)fromState toState:(LNPopupPresentationState)state +{ + UIView* userView = [self.currentContentController viewForPopupTransitionFromPresentationState:fromState toPresentationState:state]; + + if([self _validateViewForTransition:userView] == NO) + { + return nil; + } + + return userView; +} + +- (void)animateOpenTransitionIfNeededWithAnimator:(UIViewPropertyAnimator*)animator userTransitionView:(_LNPopupTransitionView*)userTransitionView userViewForTransition:(UIView*)userView otherAnimations:(void(^)(void))otherAnimations +{ + if(userView == nil) + { + return; + } + + _LNPopupTransitionOpenAnimator* handler; + if([userView conformsToProtocol:@protocol(LNPopupTransitionView)]) + { + handler = [[_LNPopupTransitionPreferredOpenAnimator alloc] initWithTransitionView:userTransitionView userView:userView popupBar:self.popupBar popupContentView:self.popupContentView]; + } + else + { + handler = [[_LNPopupTransitionGenericOpenAnimator alloc] initWithTransitionView:userTransitionView userView:userView popupBar:self.popupBar popupContentView:self.popupContentView]; + } + + [handler animateWithAnimator:animator otherAnimations:otherAnimations]; +} + +- (void)animateCloseTransitionIfNeededWithAnimator:(UIViewPropertyAnimator*)animator userTransitionView:(_LNPopupTransitionView*)userTransitionView userViewForTransition:(UIView*)userView otherAnimations:(void(^)(void))otherAnimations +{ + if(userView == nil) + { + return; + } + + _LNPopupTransitionCloseAnimator* handler; + + if([userView conformsToProtocol:@protocol(LNPopupTransitionView)]) + { + handler = [[_LNPopupTransitionPreferredCloseAnimator alloc] initWithTransitionView:userTransitionView userView:userView popupBar:self.popupBar popupContentView:self.popupContentView currentContentController:self.currentContentController containerController:self.containerController]; + } + else + { + handler = [[_LNPopupTransitionGenericCloseAnimator alloc] initWithTransitionView:userTransitionView userView:userView popupBar:self.popupBar popupContentView:self.popupContentView currentContentController:self.currentContentController containerController:self.containerController]; + } + + [handler animateWithAnimator:animator otherAnimations:otherAnimations]; +} + +- (void)_transitionToState:(LNPopupPresentationState)state notifyDelegate:(BOOL)notifyDelegate animated:(BOOL)animated useSpringAnimation:(BOOL)spring allowPopupBarAlphaModification:(BOOL)allowBarAlpha allowFeedbackGeneration:(BOOL)allowFeedbackGeneration forceFeedbackGenerationAtStart:(BOOL)forceFeedbackAtStart completion:(void(^)(void))completion { if(state == _popupControllerInternalState) { @@ -367,7 +505,6 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) _popupContentView.hidden = NO; [_currentContentController _userFacing_viewWillAppear:NO]; } -// _currentContentController.view.frame = _containerController.view.bounds; [self.popupContentView _applyBackgroundEffectWithContentViewController:_currentContentController barEffect:(id)self.popupBar.backgroundView.effect]; @@ -378,10 +515,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) [self.popupContentView.contentView layoutIfNeeded]; if(notifyDelegate == YES && state == _LNPopupPresentationStateTransitioning) { - if(@available(iOS 13.0, *)) - { - [_currentContentController _userFacing_viewIsAppearing:NO]; - } + [_currentContentController _userFacing_viewIsAppearing:NO]; [_currentContentController _userFacing_viewDidAppear:NO]; } }]; @@ -435,7 +569,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) { if(shouldNotifyDelegateWillOpen == YES) { - if(allowFeedbackGeneration == YES) + if(allowFeedbackGeneration == YES && (forceFeedbackAtStart || resolvedStyle == LNPopupInteractionStyleSnap)) { [self _generateSoftFeedbackWithIntensity:0.9]; } @@ -448,7 +582,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) if(shouldNotifyDelegateWillClose == YES) { - if(allowFeedbackGeneration == YES) + if(allowFeedbackGeneration == YES && (forceFeedbackAtStart || resolvedStyle == LNPopupInteractionStyleSnap)) { [self _generateRigidFeedbackWithIntensity:0.9]; } @@ -481,10 +615,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) if(state == LNPopupPresentationStateOpen && stateAtStart == LNPopupPresentationStateBarPresented) { - if(@available(iOS 13.0, *)) - { - [_currentContentController _userFacing_viewIsAppearing:animated]; - } + [_currentContentController _userFacing_viewIsAppearing:animated]; } }; @@ -509,12 +640,17 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) [self _cleanupGestureRecognizersForController:_currentContentController]; [_currentContentController.viewForPopupInteractionGestureRecognizer removeGestureRecognizer:self.popupContentView.popupInteractionGestureRecognizer]; - [self.popupBar addGestureRecognizer:self.popupContentView.popupInteractionGestureRecognizer]; + [self.popupBar.contentView addGestureRecognizer:self.popupContentView.popupInteractionGestureRecognizer]; [self.popupBar _setTitleViewMarqueesPaused:NO]; _popupContentView.accessibilityViewIsModal = NO; UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); + +// if(allowFeedbackGeneration == YES && (forceFeedbackAtStart == false && resolvedStyle != LNPopupInteractionStyleSnap)) +// { +// [self _generateSoftFeedbackWithIntensity:0.8]; +// } } _popupControllerInternalState = state; @@ -548,6 +684,11 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) _popupContentView.accessibilityViewIsModal = YES; UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, _popupContentView.popupCloseButton); +// if(allowFeedbackGeneration == YES && (forceFeedbackAtStart == false && resolvedStyle != LNPopupInteractionStyleSnap)) +// { +// [self _generateSoftFeedbackWithIntensity:0.8]; +// } + if(_popupControllerPublicState == LNPopupPresentationStateOpen && publicStateAtStart != _popupControllerPublicState) { if(_LNCallDelegateObjectObjectBool(_containerController, _currentContentController, @selector(popupPresentationController:didOpenPopupWithContentController:animated:), animated) == NO) @@ -565,18 +706,60 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) // [self _clearRunningPopupAnimators]; - if(animated == NO) + _LNPopupTransitionView* transitionView; + UIView* userView; + if((self.popupBar.resolvedStyle == LNPopupBarStyleProminent || self.popupBar.resolvedStyle == LNPopupBarStyleFloating) && + resolvedStyle == LNPopupInteractionStyleSnap && + ((stateAtStart == LNPopupPresentationStateBarPresented && state == LNPopupPresentationStateOpen) || + (state == LNPopupPresentationStateBarPresented))) { - [UIView performWithoutAnimation:^{ - animationBlock(); - completionBlock(UIViewAnimatingPositionEnd); - [_currentContentController.view layoutIfNeeded]; - }]; - return; + transitionView = [self _userTransitionViewForTransitionFromState:publicStateAtStart toState:state userView:&userView]; + + if(transitionView == nil) + { + userView = (id)[self _supportedUserViewForTransitionFromState:publicStateAtStart toState:state]; + } } - _runningPopupAnimation = [[UIViewPropertyAnimator alloc] initWithDuration:resolvedStyle == LNPopupInteractionStyleSnap ? 0.4 : 0.5 dampingRatio:spring ? 0.85 : 1.0 animations:animationBlock]; + CGFloat animationDuration = resolvedStyle == LNPopupInteractionStyleSnap ? 0.5 : 0.5; +#if DEBUG + if(_LNEnableSlowTransitionsDebug()) + { + animationDuration = 4.0; + } +#endif + + _runningPopupAnimation = [[UIViewPropertyAnimator alloc] initWithDuration:animationDuration dampingRatio:spring && userView == nil ? 0.85 : 1.0 animations:nil]; _runningPopupAnimation.userInteractionEnabled = NO; + + if(stateAtStart == LNPopupPresentationStateBarPresented && userView != nil) + { + [self animateOpenTransitionIfNeededWithAnimator:_runningPopupAnimation userTransitionView:transitionView userViewForTransition:userView otherAnimations:animationBlock]; + } + else if(state == LNPopupPresentationStateBarPresented && userView != nil) + { + [self animateCloseTransitionIfNeededWithAnimator:_runningPopupAnimation userTransitionView:transitionView userViewForTransition:userView otherAnimations:animationBlock]; + } + else + { + [_runningPopupAnimation addAnimations:animationBlock]; + + if(state == LNPopupPresentationStateBarPresented) + { + [_runningPopupAnimation addAnimations:^{ + if(self.containerController._ln_shouldPopupContentAnyFadeForTransition && self.containerController._ln_shouldPopupContentViewFadeForTransition) + { + self.popupContentView.alpha = 0.0; + } + } delayFactor:0.15]; + + [_runningPopupAnimation addCompletion:^(UIViewAnimatingPosition finalPosition) { + self.popupContentView.alpha = 1.0; +// self.currentContentController.view.alpha = 1.0; + }]; + } + } + [_runningPopupAnimation addCompletion:completionBlock]; [_runningPopupAnimation addCompletion:^(UIViewAnimatingPosition finalPosition) { _runningPopupAnimation = nil; @@ -584,6 +767,13 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) [self _addEventQueueResumptionStep:_runningPopupAnimation]; [_runningPopupAnimation startAnimation]; + + if(animated == NO) + { + UIViewPropertyAnimator* retained = _runningPopupAnimation; + [retained stopAnimation:NO]; + [retained finishAnimationAtPosition:UIViewAnimatingPositionEnd]; + } } - (void)_popupBarLongPressGestureRecognized:(UILongPressGestureRecognizer*)lpgr @@ -627,19 +817,20 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) - (void)_popupBarPresentationByUserPanGestureHandler_began:(UIPanGestureRecognizer*)pgr { -#if TARGET_OS_MACCATALYST - UIEvent* event = self.popupBar.window._ln_currentEvent; - if(event.type == 22 /*NSEventTypeScrollWheel*/) + if(LNPopupBar.isCatalystApp) { - return; + UIEvent* event = self.popupBar.window._ln_currentEvent; + if(event.type == 22 /*NSEventTypeScrollWheel*/) + { + return; + } + + if(event != nil && event.type == 22) + { + return; + } } - if(event != nil && event.type == 22) - { - return; - } -#endif - [self _start120HzHack]; if(self.popupBar.customBarViewController != nil && self.popupBar.customBarViewController.wantsDefaultPanGestureRecognizer == NO) @@ -665,6 +856,8 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) { if((_popupControllerInternalState == LNPopupPresentationStateBarPresented && [pgr velocityInView:self.popupBar].y < 0)) { + [self _end120HzHack]; + pgr.enabled = NO; pgr.enabled = YES; @@ -707,12 +900,10 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) - (void)_popupBarPresentationByUserPanGestureHandler_changed:(UIPanGestureRecognizer*)pgr { -#if TARGET_OS_MACCATALYST - if(self.popupBar.window._ln_currentEvent.type == 22 /*NSEventTypeScrollWheel*/) + if(LNPopupBar.isCatalystApp && self.popupBar.window._ln_currentEvent.type == 22 /*NSEventTypeScrollWheel*/) { return; } -#endif LNPopupInteractionStyle resolvedStyle = _LNPopupResolveInteractionStyleFromInteractionStyle(_containerController.popupInteractionStyle); @@ -728,16 +919,36 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) return; } + CGPoint translation = [pgr translationInView:pgr.view]; + BOOL isVerticalPan = fabs(translation.y) > fabs(translation.x); + if(pgr != _popupContentView.popupInteractionGestureRecognizer) { UIScrollView* possibleScrollView = (id)pgr.view; if([possibleScrollView isKindOfClass:[UIScrollView class]]) { + //If not scrolling only vertically, ignore the scroll view's pan gesture recognizer. + if(possibleScrollView._ln_scrollingOnlyVertically == NO) + { + if(isVerticalPan == NO) + { + _popupContentView.popupInteractionGestureRecognizer.enabled = NO; + _popupContentView.popupInteractionGestureRecognizer.enabled = YES; + } + else if(_dismissGestureStarted == YES) + { + pgr.enabled = NO; + pgr.enabled = YES; + } + + return; + } + id delegate = _popupContentView.popupInteractionGestureRecognizer.delegate; if(([delegate respondsToSelector:@selector(gestureRecognizer:shouldRequireFailureOfGestureRecognizer:)] && [delegate gestureRecognizer:_popupContentView.popupInteractionGestureRecognizer shouldRequireFailureOfGestureRecognizer:pgr] == YES) || ([delegate respondsToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)] && [delegate gestureRecognizer:_popupContentView.popupInteractionGestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:pgr] == NO) || - (_dismissGestureStarted == NO && possibleScrollView.contentOffset.y > - (possibleScrollView.contentInset.top + LNPopupBarDeveloperPanGestureThreshold))) + (_dismissGestureStarted == NO && possibleScrollView._ln_isAtTop == NO)) { return; } @@ -760,7 +971,9 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) if(_dismissGestureStarted == NO && (resolvedStyle == LNPopupInteractionStyleDrag || resolvedStyle == LNPopupInteractionStyleScroll || _popupControllerInternalState > LNPopupPresentationStateBarPresented)) { - if(resolvedStyle != LNPopupInteractionStyleSnap) + BOOL allowFeedback = (_popupControllerInternalState == LNPopupPresentationStateOpen && translation.y > 0) || (_popupControllerInternalState == LNPopupPresentationStateBarPresented && translation.y < 0); + + if(resolvedStyle != LNPopupInteractionStyleSnap && allowFeedback) { [self _generateSoftFeedbackWithIntensity:0.8]; } @@ -775,9 +988,9 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) _stateBeforeDismissStarted = _popupControllerInternalState; - [self _transitionToState:_LNPopupPresentationStateTransitioning notifyDelegate:YES animated:YES useSpringAnimation:NO allowPopupBarAlphaModification:YES allowFeedbackGeneration:NO completion:nil]; + [self _transitionToState:_LNPopupPresentationStateTransitioning notifyDelegate:YES animated:YES useSpringAnimation:NO allowPopupBarAlphaModification:YES allowFeedbackGeneration:NO forceFeedbackGenerationAtStart:NO completion:nil]; - _cachedDefaultFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + _cachedDefaultFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; _cachedInsets = [_containerController insetsForBottomDockingView]; _cachedOpenPopupFrame = [self _frameForOpenPopupBar]; @@ -838,6 +1051,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) [UIView animateWithDuration:0.3 delay:0.0 usingSpringWithDamping:500 initialSpringVelocity:0 options:0 animations:^{ [_containerController setNeedsStatusBarAppearanceUpdate]; + [_containerController setNeedsUpdateOfHomeIndicatorAutoHidden]; } completion:nil]; } } @@ -874,11 +1088,11 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) [_popupContentView.popupCloseButton _setButtonContainerStationary]; if(targetState == LNPopupPresentationStateOpen) { - [self openPopupAnimated:YES completion:nil]; + [self openPopupAnimated:YES allowFeedbackGeneration:targetState != _stateBeforeDismissStarted forceFeedbackGenerationAtStart:resolvedStyle == LNPopupInteractionStyleSnap completion:nil]; } else { - [self closePopupAnimated:YES completion:nil]; + [self closePopupAnimated:YES allowFeedbackGeneration:targetState != _stateBeforeDismissStarted forceFeedbackGenerationAtStart:resolvedStyle == LNPopupInteractionStyleSnap completion:nil]; } } @@ -995,10 +1209,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) if(_popupControllerInternalState > LNPopupPresentationStateBarPresented) { - if(@available(iOS 13.0, *)) - { - [newContentController _userFacing_viewIsAppearing:NO]; - } + [newContentController _userFacing_viewIsAppearing:NO]; [newContentController _userFacing_viewDidAppear:NO]; [newContentController endAppearanceTransition]; [oldContentController _userFacing_viewDidDisappear:NO]; @@ -1037,13 +1248,16 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) - (void)_configurePopupBarFromBottomBarModifyingGroupingIdentifier:(BOOL)modifyingGroupingIdentifier { - if(modifyingGroupingIdentifier == YES) + if(unavailable(iOS 17.0, *)) { - self.popupBar.effectGroupingIdentifier = _bottomBar._ln_effectGroupingIdentifierIfAvailable; - //Schedule one more effect identifier refresh, in case it's not yet ready at this point. - dispatch_async(dispatch_get_main_queue(), ^{ + if(modifyingGroupingIdentifier == YES) + { self.popupBar.effectGroupingIdentifier = _bottomBar._ln_effectGroupingIdentifierIfAvailable; - }); + //Schedule one more effect identifier refresh, in case it's not yet ready at this point. + dispatch_async(dispatch_get_main_queue(), ^{ + self.popupBar.effectGroupingIdentifier = _bottomBar._ln_effectGroupingIdentifierIfAvailable; + }); + } } if(self.popupBar.inheritsAppearanceFromDockingView == NO) @@ -1051,27 +1265,12 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) return; } - UIColor* bottomBarTintColor = _bottomBar.tintColor; - if(_bottomBar.window != nil || [_bottomBar.superview.tintColor isEqual:bottomBarTintColor] == NO) - { - self.popupBar.systemTintColor = bottomBarTintColor; - } - else - { - self.popupBar.systemTintColor = nil; - } - - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { UIBarAppearance* appearanceToUse = nil; #ifndef LNPopupControllerEnforceStrictClean - static NSString* vPTIS = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - //visualProvider.toolbarIsSmall - vPTIS = _LNPopupDecodeBase64String(_vPTIS); - }); + static NSString* vPTIS = LNPopupHiddenString("visualProvider.toolbarIsSmall"); //visualProvider.toolbarIsSmall if([_bottomBar isKindOfClass:UIToolbar.class] && [[_bottomBar valueForKeyPath:vPTIS] boolValue] == YES) @@ -1093,6 +1292,16 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) appearanceToUse = [(id<_LNPopupBarSupport>)_bottomBar standardAppearance]; } + UIColor* bottomBarTintColor = _bottomBar.tintColor; + if(_bottomBar.window != nil || [_bottomBar.superview.tintColor isEqual:bottomBarTintColor] == NO) + { + self.popupBar.systemTintColor = bottomBarTintColor; + } + else + { + self.popupBar.systemTintColor = nil; + } + self.popupBar.systemAppearance = appearanceToUse; } else @@ -1144,7 +1353,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) } } -- (LNPopupBar *)popupBarStorage +- (LNPopupBar*)popupBarStorage { if(_popupBar) { @@ -1156,19 +1365,24 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) _popupBar.barContainingController = _containerController; _popupBar._barDelegate = self; _popupBar.popupOpenGestureRecognizer = [[LNPopupOpenTapGestureRecognizer alloc] initWithTarget:self action:@selector(_popupBarTapGestureRecognized:)]; - [_popupBar addGestureRecognizer:_popupBar.popupOpenGestureRecognizer]; + [_popupBar.contentView addGestureRecognizer:_popupBar.popupOpenGestureRecognizer]; _popupBar.barHighlightGestureRecognizer = [[LNPopupLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_popupBarLongPressGestureRecognized:)]; _popupBar.barHighlightGestureRecognizer.minimumPressDuration = 0; _popupBar.barHighlightGestureRecognizer.cancelsTouchesInView = NO; _popupBar.barHighlightGestureRecognizer.delaysTouchesBegan = NO; _popupBar.barHighlightGestureRecognizer.delaysTouchesEnded = NO; - [_popupBar addGestureRecognizer:_popupBar.barHighlightGestureRecognizer]; + [_popupBar.contentView addGestureRecognizer:_popupBar.barHighlightGestureRecognizer]; return _popupBar; } -- (LNPopupBar *)popupBar +- (LNPopupBar*)popupBarNoCreate +{ + return _popupBar; +} + +- (LNPopupBar*)popupBar { if(_popupControllerInternalState == LNPopupPresentationStateBarHidden) { @@ -1178,7 +1392,7 @@ static CGFloat __smoothstep(CGFloat a, CGFloat b, CGFloat x) return self.popupBarStorage; } -- (LNPopupContentView *)popupContentView +- (LNPopupContentView*)popupContentView { if(_popupContentView) { @@ -1215,26 +1429,38 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v }]; } +- (void)_fixupGestureRecognizer:(UIGestureRecognizer*)obj +{ + if([obj isKindOfClass:[UIPanGestureRecognizer class]] && [obj.view isDescendantOfView:_currentContentController.viewForPopupInteractionGestureRecognizer] && obj != _popupContentView.popupInteractionGestureRecognizer) + { + [obj addTarget:self action:@selector(_popupBarPresentationByUserPanGestureHandler:)]; + } +} + - (void)_fixupGestureRecognizersForController:(UIViewController*)vc { __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(vc.viewForPopupInteractionGestureRecognizer, ^(UIView *view) { [view.gestureRecognizers enumerateObjectsUsingBlock:^(__kindof UIGestureRecognizer * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - if([obj isKindOfClass:[UIPanGestureRecognizer class]] && obj != _popupContentView.popupInteractionGestureRecognizer) - { - [obj addTarget:self action:@selector(_popupBarPresentationByUserPanGestureHandler:)]; - } + [self _fixupGestureRecognizer:obj]; }]; }); } +- (void)_unfixupGestureRecognizer:(UIGestureRecognizer*)obj +{ + if([obj isKindOfClass:[UIPanGestureRecognizer class]] && [obj.view isDescendantOfView:_currentContentController.viewForPopupInteractionGestureRecognizer] && obj != _popupContentView.popupInteractionGestureRecognizer) + { + [obj removeTarget:self action:@selector(_popupBarPresentationByUserPanGestureHandler:)]; + } +} + - (void)_cleanupGestureRecognizersForController:(UIViewController*)vc { - [vc.viewForPopupInteractionGestureRecognizer.gestureRecognizers enumerateObjectsUsingBlock:^(__kindof UIGestureRecognizer * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - if([obj isKindOfClass:[UIPanGestureRecognizer class]] && obj != _popupContentView.popupInteractionGestureRecognizer) - { - [obj removeTarget:self action:@selector(_popupBarPresentationByUserPanGestureHandler:)]; - } - }]; + __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(vc.viewForPopupInteractionGestureRecognizer, ^(UIView *view) { + [view.gestureRecognizers enumerateObjectsUsingBlock:^(__kindof UIGestureRecognizer * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + [self _unfixupGestureRecognizer:obj]; + }]; + }); } - (BOOL)_hasRunningAnimators @@ -1285,15 +1511,17 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v //{ // if(_runningBarAnimation != nil) // { -// [_runningBarAnimation stopAnimation:NO]; -// [_runningBarAnimation finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; +// UIViewPropertyAnimator* retained = _runningBarAnimation; +// [retained stopAnimation:NO]; +// [retained finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; // _runningBarAnimation = nil; // } // // if(_runningBarSidecarAnimation != nil) // { -// [_runningBarSidecarAnimation stopAnimation:NO]; -// [_runningBarSidecarAnimation finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; +// UIViewPropertyAnimator* retained = _runningBarSidecarAnimation; +// [retained stopAnimation:NO]; +// [retained finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; // _runningBarSidecarAnimation = nil; // } //} @@ -1302,8 +1530,9 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v //{ // if(_runningPopupAnimation != nil) // { -// [_runningPopupAnimation stopAnimation:NO]; -// [_runningPopupAnimation finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; +// UIViewPropertyAnimator* retained = _runningPopupAnimation; +// [retained stopAnimation:NO]; +// [retained finishAnimationAtPosition:UIViewAnimatingPositionCurrent]; // _runningPopupAnimation = nil; // } //} @@ -1338,7 +1567,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v } _popupControllerTargetState = LNPopupPresentationStateBarPresented; - _bottomBar = _containerController.bottomDockingViewForPopup_internalOrDeveloper; + self.bottomBar = _containerController.bottomDockingViewForPopup_internalOrDeveloper; _bottomBar.attachedPopupController = self; self.popupBarStorage.hidden = NO; @@ -1346,7 +1575,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v [self _movePopupBarAndContentToBottomBarSuperview]; [self _configurePopupBarFromBottomBar]; - [self.popupBar addGestureRecognizer:self.popupContentView.popupInteractionGestureRecognizer]; + [self.popupBar.contentView addGestureRecognizer:self.popupContentView.popupInteractionGestureRecognizer]; [self _setContentToState:LNPopupPresentationStateBarPresented animated:animated]; @@ -1359,7 +1588,10 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v _LNCallDelegateObjectBool(_containerController, @selector(popupPresentationControllerWillPresentPopupBar:animated:), animated); [self.popupBar.customBarViewController _userFacing_viewWillAppear:animated]; - [_bottomBar _ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:YES]; + if(@available(iOS 13.0, *)) + { + [_bottomBar _ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:YES]; + } _containerController._ln_bottomBarExtension_nocreate.alpha = 1.0; CGRect barFrame = self.popupBar.frame; @@ -1371,12 +1603,9 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v [self.popupBar setNeedsLayout]; [self.popupBar layoutIfNeeded]; - if(@available(iOS 13.0, *)) - { - [self.popupBar.customBarViewController _userFacing_viewIsAppearing:animated]; - } + [self.popupBar.customBarViewController _userFacing_viewIsAppearing:animated]; - _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsMake(0, 0, barFrame.size.height, 0)); + _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsMake(0, 0, barFrame.size.height - [_containerController _ln_popupOffsetForPopupBarStyle:self.popupBar.resolvedStyle], 0)); if(open) { @@ -1387,7 +1616,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v _LNCallDelegateObjectBool(_containerController, @selector(popupPresentationControllerWillOpenPopup:animated:), animated); } - [self _openPopupAnimated:animated completion:completionBlock]; + [self _openPopupAnimated:animated allowFeedbackGeneration:YES forceFeedbackGenerationAtStart:YES completion:completionBlock]; } }; @@ -1437,10 +1666,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v _runningBarAnimation = nil; }]; [self _addEventQueueResumptionStep:_runningBarAnimation]; - if(animated == NO) - { - _runningBarAnimation.fractionComplete = 1.0; - } + [_runningBarAnimation startAnimation]; _runningBarSidecarAnimation = [[UIViewPropertyAnimator alloc] initWithDuration:0.3 dampingRatio:500 animations:middle]; @@ -1450,8 +1676,16 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v [self _addEventQueueResumptionStep:_runningBarSidecarAnimation]; if(animated == NO) { - _runningBarSidecarAnimation.fractionComplete = 1.0; [_runningBarSidecarAnimation startAnimation]; + + UIViewPropertyAnimator* retained1 = _runningBarAnimation; + UIViewPropertyAnimator* retained2 = _runningBarSidecarAnimation; + + [retained1 stopAnimation:NO]; + [retained1 finishAnimationAtPosition:UIViewAnimatingPositionEnd]; + + [retained2 stopAnimation:NO]; + [retained2 finishAnimationAtPosition:UIViewAnimatingPositionEnd]; } else { @@ -1479,13 +1713,18 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v } - (void)openPopupAnimated:(BOOL)animated completion:(void(^)(void))completionBlock +{ + [self openPopupAnimated:animated allowFeedbackGeneration:YES forceFeedbackGenerationAtStart:YES completion:completionBlock]; +} + +- (void)openPopupAnimated:(BOOL)animated allowFeedbackGeneration:(BOOL)allowFeedbackGeneration forceFeedbackGenerationAtStart:(BOOL)forceFeedbackAtStart completion:(void(^)(void))completionBlock { [self _enqueueEvent:[_LNPopupControllerEvent openEventWithOperation:^{ - [self _openPopupAnimated:animated completion:completionBlock]; + [self _openPopupAnimated:animated allowFeedbackGeneration:allowFeedbackGeneration forceFeedbackGenerationAtStart:forceFeedbackAtStart completion:completionBlock]; }]]; } -- (void)_openPopupAnimated:(BOOL)animated completion:(void(^)(void))completionBlock +- (void)_openPopupAnimated:(BOOL)animated allowFeedbackGeneration:(BOOL)allowFeedbackGeneration forceFeedbackGenerationAtStart:(BOOL)forceFeedbackAtStart completion:(void(^)(void))completionBlock { [self _start120HzHack]; @@ -1493,7 +1732,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v { [_containerController.view setNeedsLayout]; [_containerController.view layoutIfNeeded]; - [self _transitionToState:LNPopupPresentationStateOpen notifyDelegate:YES animated:animated useSpringAnimation:NO allowPopupBarAlphaModification:YES allowFeedbackGeneration:YES completion:completionBlock]; + [self _transitionToState:LNPopupPresentationStateOpen notifyDelegate:YES animated:animated useSpringAnimation:NO allowPopupBarAlphaModification:YES allowFeedbackGeneration:allowFeedbackGeneration forceFeedbackGenerationAtStart:forceFeedbackAtStart completion:completionBlock]; } else if(completionBlock != nil) { @@ -1502,19 +1741,24 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v } - (void)closePopupAnimated:(BOOL)animated completion:(void(^)(void))completionBlock +{ + [self closePopupAnimated:animated allowFeedbackGeneration:YES forceFeedbackGenerationAtStart:YES completion:completionBlock]; +} + +- (void)closePopupAnimated:(BOOL)animated allowFeedbackGeneration:(BOOL)allowFeedbackGeneration forceFeedbackGenerationAtStart:(BOOL)forceFeedbackAtStart completion:(void(^)(void))completionBlock { [self _enqueueEvent:[_LNPopupControllerEvent closeEventWithOperation:^{ - [self _closePopupAnimated:animated completion:completionBlock]; + [self _closePopupAnimated:animated allowFeedbackGeneration:allowFeedbackGeneration forceFeedbackGenerationAtStart:forceFeedbackAtStart completion:completionBlock]; }]]; } -- (void)_closePopupAnimated:(BOOL)animated completion:(void(^)(void))completionBlock +- (void)_closePopupAnimated:(BOOL)animated allowFeedbackGeneration:(BOOL)allowFeedbackGeneration forceFeedbackGenerationAtStart:(BOOL)forceFeedbackAtStart completion:(void(^)(void))completionBlock { if(_popupControllerTargetState != LNPopupPresentationStateBarPresented) { LNPopupInteractionStyle resolvedStyle = _LNPopupResolveInteractionStyleFromInteractionStyle(_containerController.popupInteractionStyle); - [self _transitionToState:LNPopupPresentationStateBarPresented notifyDelegate:YES animated:animated useSpringAnimation:resolvedStyle == LNPopupInteractionStyleSnap ? YES : NO allowPopupBarAlphaModification:YES allowFeedbackGeneration:YES completion:completionBlock]; + [self _transitionToState:LNPopupPresentationStateBarPresented notifyDelegate:YES animated:animated useSpringAnimation:resolvedStyle == LNPopupInteractionStyleSnap ? YES : NO allowPopupBarAlphaModification:YES allowFeedbackGeneration:allowFeedbackGeneration forceFeedbackGenerationAtStart:forceFeedbackAtStart completion:completionBlock]; } else if(completionBlock != nil) { @@ -1552,10 +1796,23 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v // [self _clearRunningBarAnimators]; // [self _clearRunningPopupAnimators]; - _runningBarAnimation = [[UIViewPropertyAnimator alloc] initWithDuration:animated ? 0.5 : 0.0 dampingRatio:500 animations:^{ + __weak decltype(self) weakSelf = self; + + _runningBarAnimation = [[UIViewPropertyAnimator alloc] initWithDuration:0.5 dampingRatio:500 animations:^{ + __strong decltype(weakSelf) self = weakSelf; + if(self == nil) + { + return; + } + _LNCallDelegateObjectBool(_containerController, @selector(popupPresentationControllerWillDismissPopupBar:animated:), animated); [self.popupBar.customBarViewController _userFacing_viewWillDisappear:animated]; + if(@available(iOS 13.0, *)) + { + [_bottomBar _ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:YES]; + } + CGRect barFrame = self.popupBar.frame; barFrame.size.height = 0; self.popupBar.frame = barFrame; @@ -1565,8 +1822,6 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v self.popupBar.shadowView.alpha = 0.0; _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsZero); - [_bottomBar _ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:YES]; - CGFloat currentBarAlpha = self.popupBarStorage.alpha; [UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:500 initialSpringVelocity:0 options:UIViewAnimationOptionAllowAnimatedContent animations:^{ if(_containerController.shouldFadePopupBarOnDismiss) @@ -1579,7 +1834,13 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v }]; }]; - [_runningBarAnimation addCompletion:^(UIViewAnimatingPosition finalPosition) { + [_runningBarAnimation addCompletion:^(UIViewAnimatingPosition finalPosition) { + __strong decltype(weakSelf) self = weakSelf; + if(self == nil) + { + return; + } + if(finalPosition != UIViewAnimatingPositionEnd) { return; @@ -1593,7 +1854,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v [self _removeContentControllerFromContentView:_currentContentController]; - CGRect bottomBarFrame = [_containerController defaultFrameForBottomDockingView_internalOrDeveloper]; + CGRect bottomBarFrame = [_containerController _defaultFrameForBottomDockingViewForPopupBar:_popupBar]; bottomBarFrame.origin.y -= _cachedInsets.bottom; _bottomBar.frame = bottomBarFrame; @@ -1615,7 +1876,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v _LNCallDelegateObjectBool(_containerController, @selector(popupPresentationControllerDidDismissPopupBar:animated:), animated); _bottomBar.attachedPopupController = nil; - _bottomBar = nil; + self.bottomBar = nil; [self _end120HzHack]; @@ -1625,7 +1886,15 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v _runningBarAnimation = nil; }]; [self _addEventQueueResumptionStep:_runningBarAnimation]; + [_runningBarAnimation startAnimation]; + + if(animated == NO) + { + UIViewPropertyAnimator* retained = _runningBarAnimation; + [retained stopAnimation:NO]; + [retained finishAnimationAtPosition:UIViewAnimatingPositionEnd]; + } }; _dismissalOverride = YES; @@ -1637,7 +1906,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v LNPopupInteractionStyle resolvedStyle = _LNPopupResolveInteractionStyleFromInteractionStyle(_containerController.popupInteractionStyle); - [self _transitionToState:LNPopupPresentationStateBarPresented notifyDelegate:YES animated:animated useSpringAnimation:resolvedStyle == LNPopupInteractionStyleSnap allowPopupBarAlphaModification:YES allowFeedbackGeneration:YES completion:dismissalAnimationCompletionBlock]; + [self _transitionToState:LNPopupPresentationStateBarPresented notifyDelegate:YES animated:animated useSpringAnimation:resolvedStyle == LNPopupInteractionStyleSnap allowPopupBarAlphaModification:YES allowFeedbackGeneration:YES forceFeedbackGenerationAtStart:YES completion:dismissalAnimationCompletionBlock]; } else { @@ -1673,6 +1942,11 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v } - (void)_popupBarMetricsDidChange:(LNPopupBar*)bar +{ + [self _popupBarMetricsDidChange:bar shouldLayout:YES]; +} + +- (void)_popupBarMetricsDidChange:(LNPopupBar*)bar shouldLayout:(BOOL)layout { if(self.popupBar.acceptsSizing == NO) { @@ -1686,13 +1960,16 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v barFrame.origin.y -= (barFrame.size.height - currentHeight); self.popupBar.frame = barFrame; - _LNPopupSupportSetPopupInsetsForViewController(_containerController, YES, UIEdgeInsetsMake(0, 0, self.popupBar.frame.size.height, 0)); + _LNPopupSupportSetPopupInsetsForViewController(_containerController, layout, UIEdgeInsetsMake(0, 0, self.popupBar.frame.size.height - [_containerController _ln_popupOffsetForPopupBarStyle:self.popupBar.resolvedStyle], 0)); } - (void)_popupBarStyleDidChange:(LNPopupBar*)bar { [self _updateBarExtensionStyleFromPopupBar]; - [_containerController.popupBar _applyGroupingIdentifierToVisualEffectView:self.popupContentView.effectView]; + if(LNPopupBar.isCatalystApp == NO) + { + [_containerController.popupBar _applyGroupingIdentifierToVisualEffectView:self.popupContentView.effectView]; + } } - (void)_popupBar:(LNPopupBar *)bar updateCustomBarController:(LNPopupCustomBarViewController *)customController cleanup:(BOOL)cleanup @@ -1713,7 +1990,7 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - if (@available(iOS 15.0, *)) + if(@available(iOS 15.0, *)) { if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone && UIScreen.mainScreen.maximumFramesPerSecond > 60 && [[NSBundle.mainBundle objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"] boolValue] == NO) { @@ -1756,9 +2033,11 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v + (CGFloat)_statusBarHeightForView:(UIView*)view { -#if TARGET_OS_MACCATALYST - return 0; -#else + if(LNPopupBar.isCatalystApp) + { + return 0; + } + if(view == nil || view.window == nil) { return 0; @@ -1767,15 +2046,17 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v if(view.window.safeAreaInsets.top == 0) { //Probably 🤷â€�♂ï¸� an old iPhone - if (@available(iOS 13.0, *)) { + if(@available(iOS 13.0, *)) + { return view.window.windowScene.statusBarManager.statusBarHidden ? 0 : 20; - } else { + } + else + { return UIApplication.sharedApplication.statusBarFrame.size.height; } } return view.window.safeAreaInsets.top; -#endif } - (void)_120HzTick {} @@ -1824,10 +2105,9 @@ static void __LNPopupControllerDeeplyEnumerateSubviewsUsingBlock(UIView* view, v - (void)_popupItem_update_standardAppearance { - if (@available(iOS 13.0, *)) - { - [self.popupBarStorage _recalcActiveAppearanceChain]; - } + [self.popupBarStorage _recalcActiveAppearanceChain]; } @end + +CF_EXTERN_C_END diff --git a/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController+Private.h b/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController+Private.h index 7936ebf..76a6537 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController+Private.h +++ b/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController+Private.h @@ -2,8 +2,8 @@ // LNPopupItem+Private.h // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2016-12-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController.m b/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController.m index a9c8090..bb9cd6e 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController.m +++ b/LNPopupController/LNPopupController/Private/LNPopupCustomBarViewController.m @@ -2,8 +2,8 @@ // LNPopupBarContentViewController.m // LNPopupController // -// Created by Leo Natan on 15/12/2016. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2016-12-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupCustomBarViewController+Private.h" @@ -126,7 +126,7 @@ __ln_popup_suppressViewControllerLifecycle = NO; } -- (void)_userFacing_viewIsAppearing:(BOOL)animated +- (void)_userFacing_viewIsAppearing:(BOOL)animated API_AVAILABLE(ios(13.0)) { __ln_popup_suppressViewControllerLifecycle = YES; diff --git a/LNPopupController/LNPopupController/Private/LNPopupDebug.h b/LNPopupController/LNPopupController/Private/LNPopupDebug.h new file mode 100644 index 0000000..55b096c --- /dev/null +++ b/LNPopupController/LNPopupController/Private/LNPopupDebug.h @@ -0,0 +1,19 @@ +// +// LNPopupDebug.h +// LNPopupController +// +// Created by Léo Natan on 4/4/25. +// Copyright © 2025 Léo Natan. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifdef DEBUG +CF_EXTERN_C_BEGIN +extern NSUserDefaults* __LNDebugUserDefaults(void); +CF_EXTERN_C_END +#endif + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/LNPopupDebug.m b/LNPopupController/LNPopupController/Private/LNPopupDebug.m new file mode 100644 index 0000000..28df9fe --- /dev/null +++ b/LNPopupController/LNPopupController/Private/LNPopupDebug.m @@ -0,0 +1,31 @@ +// +// LNPopupDebug.m +// LNPopupController +// +// Created by Léo Natan on 4/4/25. +// Copyright © 2025 Léo Natan. All rights reserved. +// + +#import "LNPopupDebug.h" + +#ifdef DEBUG +NSUserDefaults* __LNDebugUserDefaults(void) +{ + static NSUserDefaults* rv = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + SEL sel = NSSelectorFromString(@"settingDefaults"); + if([NSUserDefaults respondsToSelector:sel]) + { + rv = [NSUserDefaults valueForKey:@"settingDefaults"]; + } + else + { + rv = NSUserDefaults.standardUserDefaults; + } + }); + + return rv; +} +#endif diff --git a/LNPopupController/LNPopupController/Private/LNPopupImageView+Private.h b/LNPopupController/LNPopupController/Private/LNPopupImageView+Private.h new file mode 100644 index 0000000..646b539 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/LNPopupImageView+Private.h @@ -0,0 +1,20 @@ +// +// LNPopupImageView+Private.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import +#import "LNPopupBar+Private.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface LNPopupImageView () + +- (instancetype)initWithContainingPopupBar:(LNPopupBar*)popupBar; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/LNPopupImageView.mm b/LNPopupController/LNPopupController/Private/LNPopupImageView.mm new file mode 100644 index 0000000..4c06cdf --- /dev/null +++ b/LNPopupController/LNPopupController/Private/LNPopupImageView.mm @@ -0,0 +1,255 @@ +// +// LNPopupImageView.mm +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "LNPopupImageView+Private.h" +#import "_LNPopupBase64Utils.hh" +#import "UIViewController+LNPopupSupportPrivate.h" +#import + +@interface _LNPopupBarShadowedImageViewLayer : CALayer @end +@implementation _LNPopupBarShadowedImageViewLayer +{ + @public + __weak CALayer* _imageContentsLayer; +} + +- (void)setMasksToBounds:(BOOL)masksToBounds +{ + [super setMasksToBounds:NO]; +} + +- (void)addSublayer:(CALayer *)layer +{ + layer.masksToBounds = YES; + if(@available(iOS 13.0, *)) + { + layer.cornerCurve = kCACornerCurveContinuous; + } + layer.cornerRadius = _imageContentsLayer.cornerRadius; + [super addSublayer:layer]; +} + +- (void)layoutSublayers +{ + [super layoutSublayers]; + _imageContentsLayer.frame = self.bounds; +} + +- (void)setCornerRadius:(CGFloat)cornerRadius +{ + [(LNPopupImageView*)self.delegate setCornerRadius:cornerRadius]; +} + +- (void)setSuperCornerRadius:(CGFloat)cornerRadius +{ + _imageContentsLayer.cornerRadius = cornerRadius; + for(CALayer* sublayer in self.sublayers) + { + if(sublayer != _imageContentsLayer) + { + sublayer.cornerRadius = cornerRadius; + } + } +} + +- (void)setContents:(id)contents +{ + [_imageContentsLayer setContents:contents]; +} + +- (void)setContentsRect:(CGRect)contentsRect +{ + [_imageContentsLayer setContentsRect:contentsRect]; +} + +- (void)setContentsScale:(CGFloat)contentsScale +{ + [_imageContentsLayer setContentsScale:contentsScale]; +} + +- (void)setContentsCenter:(CGRect)contentsCenter +{ + [_imageContentsLayer setContentsCenter:contentsCenter]; +} + +- (void)setContentsFormat:(CALayerContentsFormat)contentsFormat +{ + [_imageContentsLayer setContentsFormat:contentsFormat]; +} + +- (void)setContentsGravity:(CALayerContentsGravity)contentsGravity +{ + [_imageContentsLayer setContentsGravity:contentsGravity]; +} + +- (void)setWantsExtendedDynamicRangeContent:(BOOL)wantsExtendedDynamicRangeContent +{ + [super setWantsExtendedDynamicRangeContent:wantsExtendedDynamicRangeContent]; + [_imageContentsLayer setWantsExtendedDynamicRangeContent:wantsExtendedDynamicRangeContent]; +} + +- (void)setImageContentsLayer:(CALayer*)layer +{ + _imageContentsLayer = layer; +} + +@end + +@implementation LNPopupImageView +{ + __weak LNPopupBar* _containingBar; +} + ++ (Class)layerClass +{ + return [_LNPopupBarShadowedImageViewLayer class]; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + + if(self) + { + [self _commonInit]; + } + + return self; +} + +- (instancetype)initWithImage:(UIImage *)image +{ + return [self initWithImage:image highlightedImage:nil]; +} + +- (instancetype)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage +{ + self = [super initWithImage:image highlightedImage:highlightedImage]; + + if(self) + { + [self _commonInit]; + } + + return self; +} + +- (id)actionForLayer:(CALayer *)layer forKey:(NSString *)event +{ + id rv = [super actionForLayer:layer forKey:event]; + + return rv; +} + +- (instancetype)initWithContainingPopupBar:(LNPopupBar *)popupBar +{ + self = [self initWithFrame:CGRectZero]; + + if(self) + { + _containingBar = popupBar; + } + + return self; +} + +- (void)_commonInit +{ + super.contentMode = UIViewContentModeScaleAspectFit; + self.clipsToBounds = NO; + + UIView* imageContentsLayerView = [[UIView alloc] initWithFrame:self.bounds]; + imageContentsLayerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self addSubview:imageContentsLayerView]; + [(_LNPopupBarShadowedImageViewLayer*)self.layer setImageContentsLayer:imageContentsLayerView.layer]; +} + +- (void)setShadow:(NSShadow *)shadow +{ + _shadow = shadow; + + self.layer.shadowOffset = _shadow.shadowOffset; + self.layer.shadowRadius = _shadow.shadowBlurRadius; + + [self _updateShadowColor]; + [self setNeedsLayout]; +} + +- (void)_updateShadowColor +{ + if([_shadow.shadowColor isKindOfClass:UIColor.class]) + { + self.layer.shadowColor = [_shadow.shadowColor CGColor]; + } + else + { + self.layer.shadowColor = (__bridge CGColorRef)_shadow.shadowColor; + } + self.layer.shadowOpacity = _shadow != nil ? 1.0 : 0.0; +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection +{ + [super traitCollectionDidChange:previousTraitCollection]; + + self.layer.rasterizationScale = self.traitCollection.displayScale; + [self _updateShadowColor]; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; +} + +- (void)setCornerRadius:(CGFloat)cornerRadius +{ + _cornerRadius = cornerRadius; + [(_LNPopupBarShadowedImageViewLayer*)self.layer setSuperCornerRadius:cornerRadius]; +} + +- (void)setContentMode:(UIViewContentMode)contentMode +{ + if(self.contentMode != contentMode) + { + [super setContentMode:contentMode]; + + [_containingBar setNeedsLayout]; + } +} + +- (void)setImage:(UIImage *)image +{ + if(self.image != image && [self.image isEqual:image] == NO) + { + [super setImage:image]; + + [_containingBar setNeedsLayout]; + } +} + +- (void)didMoveToWindow +{ + if(self.window == nil || _containingBar != nil) + { + return; + } + + static NSString* vCFA = LNPopupHiddenString("_viewControllerForAncestor"); + + UIViewController* candidate = [self valueForKey:vCFA]; + candidate.ln_discoveredTransitionView = self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ cornerRadius: %@ shadow: %@", super.description, @(self.cornerRadius), self.shadow]; +} + +@end + +@implementation LNPopupImageView (TransitionSupport) @end diff --git a/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.h b/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.h index a8cd4fa..34bc6e6 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.h +++ b/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.h @@ -2,8 +2,8 @@ // LNPopupInteractionPanGestureRecognizer.h // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.m b/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.m index be79266..13308ce 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.m +++ b/LNPopupController/LNPopupController/Private/LNPopupInteractionPanGestureRecognizer.m @@ -2,14 +2,15 @@ // LNPopupInteractionPanGestureRecognizer.m // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupInteractionPanGestureRecognizer.h" #import "LNForwardingDelegate.h" #import "UIViewController+LNPopupSupportPrivate.h" #import "LNPopupController.h" +#import "UIView+LNPopupSupportPrivate.h" extern LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionStyle(LNPopupInteractionStyle style); @@ -64,6 +65,11 @@ extern LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionSty return rv; } +//- (BOOL)_panGestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer shouldTryToBeginHorizontallyWithEvent:(UIEvent*)event +//{ +// return NO; +//} + - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { if([NSStringFromClass(otherGestureRecognizer.view.class) containsString:@"DropShadow"]) @@ -82,6 +88,14 @@ extern LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionSty return YES; } + //View hierarchy might add more and more views with gesture recognizers. Let's try to "import" them for our system. + [_popupController _fixupGestureRecognizer:otherGestureRecognizer]; + + if([otherGestureRecognizer.view isKindOfClass:UIScrollView.class] && [(UIScrollView*)otherGestureRecognizer.view _ln_hasVerticalContent] == NO && [(UIScrollView*)otherGestureRecognizer.view _ln_hasHorizontalContent] == NO) + { + return YES; + } + if(_popupController.popupControllerInternalState != LNPopupPresentationStateOpen) { if([self.forwardedDelegate respondsToSelector:_cmd]) @@ -111,7 +125,7 @@ extern LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionSty } else { - return YES; + return [(UIScrollView*)otherGestureRecognizer.view _ln_hasVerticalContent] == YES; } } @@ -139,6 +153,11 @@ extern LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionSty { return NO; } + + if([otherGestureRecognizer.view isKindOfClass:UIScrollView.class] && [(UIScrollView*)otherGestureRecognizer.view _ln_hasVerticalContent] == NO) + { + return NO; + } if([NSStringFromClass(otherGestureRecognizer.view.class) containsString:@"SwiftUI"]) { @@ -170,6 +189,11 @@ extern LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionSty - (id)delegate { + if([LNForwardingDelegate isCallerUIKit:NSThread.callStackReturnAddresses]) + { + return _actualDelegate; + } + return _actualDelegate.forwardedDelegate; } diff --git a/LNPopupController/LNPopupController/Private/LNPopupItem+Private.h b/LNPopupController/LNPopupController/Private/LNPopupItem+Private.h index 63ec4c0..36b6fab 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupItem+Private.h +++ b/LNPopupController/LNPopupController/Private/LNPopupItem+Private.h @@ -2,8 +2,8 @@ // LNPopupItem+Private.h // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNPopupItem.m b/LNPopupController/LNPopupController/Private/LNPopupItem.m index 92ddcd9..936f72e 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupItem.m +++ b/LNPopupController/LNPopupController/Private/LNPopupItem.m @@ -2,8 +2,8 @@ // LNPopupItem.m // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupItem+Private.h" diff --git a/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.h b/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.h index da0e13b..09ae4b5 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.h +++ b/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.h @@ -2,8 +2,8 @@ // LNPopupLongPressGestureRecognizer.h // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.m b/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.m index e019cce..812e4b3 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.m +++ b/LNPopupController/LNPopupController/Private/LNPopupLongPressGestureRecognizer.m @@ -2,8 +2,8 @@ // LNPopupLongPressGestureRecognizer.m // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupLongPressGestureRecognizer.h" @@ -17,7 +17,7 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { #if ! TARGET_OS_MACCATALYST - if (@available(iOS 13.4, *)) + if(@available(iOS 13.4, *)) { if(touch.type == UITouchTypeIndirectPointer) { diff --git a/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.h b/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.h index 6bbb97a..dac8d34 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.h +++ b/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.h @@ -2,8 +2,8 @@ // LNPopupOpenTapGestureRecognizer.h // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.m b/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.m index 707afbd..3e5e990 100644 --- a/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.m +++ b/LNPopupController/LNPopupController/Private/LNPopupOpenTapGestureRecognizer.m @@ -2,8 +2,8 @@ // LNPopupOpenTapGestureRecognizer.m // LNPopupController // -// Created by Leo Natan on 15/07/2017. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2017-07-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "LNPopupOpenTapGestureRecognizer.h" diff --git a/LNPopupController/LNPopupController/Private/MarqueeLabel.h b/LNPopupController/LNPopupController/Private/MarqueeLabel.h index a4f4091..e48de36 100755 --- a/LNPopupController/LNPopupController/Private/MarqueeLabel.h +++ b/LNPopupController/LNPopupController/Private/MarqueeLabel.h @@ -6,15 +6,15 @@ // Copyright (c) 2011-2015 Charles Powell. All rights reserved. // -#define MarqueeLabel __MarqueeLabel -#define MarqueeType __MarqueeType -#define MLLeftRight __MLLeftRight -#define MLRightLeft __MLRightLeft -#define MLContinuous __MLContinuous -#define MLContinuousReverse __MLContinuousReverse -#define MLLeft __MLLeft -#define MLRight __MLRight -#define GradientSetupAnimation __GradientSetupAnimation +#define MarqueeLabel LNMarqueeLabel +#define MarqueeType LNMarqueeType +#define MLLeftRight LNMLLeftRight +#define MLRightLeft LNMLRightLeft +#define MLContinuous LNMLContinuous +#define MLContinuousReverse LNMLContinuousReverse +#define MLLeft LNMLLeft +#define MLRight LNMLRight +#define GradientSetupAnimation LNGradientSetupAnimation #import diff --git a/LNPopupController/LNPopupController/Private/MarqueeLabel.m b/LNPopupController/LNPopupController/Private/MarqueeLabel.m index e8f6da5..20f97e7 100755 --- a/LNPopupController/LNPopupController/Private/MarqueeLabel.m +++ b/LNPopupController/LNPopupController/Private/MarqueeLabel.m @@ -39,6 +39,9 @@ typedef void(^MLAnimationCompletionBlock)(BOOL finished); @end @interface MarqueeLabel() +{ + MarqueeType _userMarqueeType; +} @property (nonatomic, strong) UILabel *subLabel; @@ -279,6 +282,8 @@ CGPoint MLOffsetCGPoint(CGPoint point, CGFloat offset); - (void)layoutSubviews { [super layoutSubviews]; + + [self _updateEffectiveMarqueeType]; [self updateSublabel]; } @@ -356,10 +361,6 @@ CGPoint MLOffsetCGPoint(CGPoint point, CGFloat offset); return; } - // Label DOES need to scroll - - [self.subLabel setLineBreakMode:NSLineBreakByClipping]; - // Spacing between primary and second sublabel must be at least equal to leadingBuffer, and at least equal to the fadeLength CGFloat minTrailing = MAX(MAX(self.leadingBuffer, self.trailingBuffer), self.fadeLength); @@ -968,7 +969,7 @@ CGPoint MLOffsetCGPoint(CGPoint point, CGFloat offset); // Create new animation CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:property]; - if (@available(iOS 15.0, *)) + if(@available(iOS 15.0, *)) { CGFloat max = UIScreen.mainScreen.maximumFramesPerSecond; animation.preferredFrameRateRange = CAFrameRateRangeMake(max, max, max); @@ -1467,12 +1468,28 @@ CGPoint MLOffsetCGPoint(CGPoint point, CGFloat offset); } } +- (void)_updateEffectiveMarqueeType +{ + BOOL isRTL = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft; + + if(isRTL) + { + _marqueeType = _userMarqueeType == MLContinuous ? MLContinuousReverse : MLContinuous; + } + else + { + _marqueeType = _userMarqueeType == MLContinuous ? MLContinuous : MLContinuousReverse; + } +} + - (void)setMarqueeType:(MarqueeType)marqueeType { - if (marqueeType == _marqueeType) { + if (marqueeType == _userMarqueeType) { return; } - _marqueeType = marqueeType; + _userMarqueeType = marqueeType; + + [self _updateEffectiveMarqueeType]; [self updateSublabel]; } diff --git a/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.h b/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.h index f463f84..865cb7b 100644 --- a/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.h +++ b/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.h @@ -2,8 +2,8 @@ // NSAttributedString+LNPopupSupport.h // LNPopupController // -// Created by Leo Natan on 9/19/21. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-09-19. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.m b/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.m index 924a389..2cecda8 100644 --- a/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.m +++ b/LNPopupController/LNPopupController/Private/NSAttributedString+LNPopupSupport.m @@ -2,8 +2,8 @@ // NSAttributedString+LNPopupSupport.m // LNPopupController // -// Created by Leo Natan on 9/19/21. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-09-19. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "NSAttributedString+LNPopupSupport.h" diff --git a/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.h b/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.h index 22f8867..6e4c9f1 100644 --- a/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.h +++ b/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.h @@ -2,8 +2,8 @@ // UIContextMenuInteraction+LNPopupSupportPrivate.h // LNPopupController // -// Created by Leo Natan on 3/28/21. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-03-28. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.m b/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.mm similarity index 79% rename from LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.m rename to LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.mm index 42dcf17..561d3f8 100644 --- a/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.m +++ b/LNPopupController/LNPopupController/Private/UIContextMenuInteraction+LNPopupSupportPrivate.mm @@ -2,22 +2,17 @@ // UIContextMenuInteraction+LNPopupSupportPrivate.m // LNPopupController // -// Created by Leo Natan on 3/28/21. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-03-28. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "UIViewController+LNPopupSupportPrivate.h" #import "UIContextMenuInteraction+LNPopupSupportPrivate.h" #import "LNPopupBar+Private.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" #ifndef LNPopupControllerEnforceStrictClean -//_delegate_previewForHighlightingForConfiguration: -static NSString* const dPFHFCBase64 = @"X2RlbGVnYXRlX3ByZXZpZXdGb3JIaWdobGlnaHRpbmdGb3JDb25maWd1cmF0aW9uOg=="; -//_delegate_contextMenuInteractionWillEndForConfiguration:presentation: -static NSString* const dCMIWEFCpBase64 = @"X2RlbGVnYXRlX2NvbnRleHRNZW51SW50ZXJhY3Rpb25XaWxsRW5kRm9yQ29uZmlndXJhdGlvbjpwcmVzZW50YXRpb246"; -//_delegate_contextMenuInteractionWillDisplayForConfiguration: -static NSString* const dCMIWDFCBase64 = @"X2RlbGVnYXRlX2NvbnRleHRNZW51SW50ZXJhY3Rpb25XaWxsRGlzcGxheUZvckNvbmZpZ3VyYXRpb246"; @implementation UIContextMenuInteraction (LNPopupSupportPrivate) @@ -25,20 +20,17 @@ static NSString* const dCMIWDFCBase64 = @"X2RlbGVnYXRlX2NvbnRleHRNZW51SW50ZXJhY3 { @autoreleasepool { - //_delegate_previewForHighlightingForConfiguration: - NSString* selName = _LNPopupDecodeBase64String(dPFHFCBase64); + NSString* selName = LNPopupHiddenString("_delegate_previewForHighlightingForConfiguration:"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_ln_d_pFHFC:)); - //_delegate_contextMenuInteractionWillEndForConfiguration:presentation: - selName = _LNPopupDecodeBase64String(dCMIWEFCpBase64); + selName = LNPopupHiddenString("_delegate_contextMenuInteractionWillEndForConfiguration:presentation:"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_ln_d_cMIWEFC:p:)); - //_delegate_contextMenuInteractionWillDisplayForConfiguration: - selName = _LNPopupDecodeBase64String(dCMIWDFCBase64); + selName = LNPopupHiddenString("_delegate_contextMenuInteractionWillDisplayForConfiguration:"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_ln_d_cMIWDFC:)); diff --git a/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.h b/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.h index 1601e0a..8a12704 100644 --- a/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.h +++ b/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.h @@ -2,8 +2,8 @@ // UIView+LNPopupSupportPrivate.h // LNPopupController // -// Created by Leo Natan on 8/1/20. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2020-08-01. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -21,24 +21,32 @@ typedef void (^LNInWindowBlock)(dispatch_block_t); @end +UIEdgeInsets _LNEdgeInsetsFromDirectionalEdgeInsets(UIView* forView, NSDirectionalEdgeInsets edgeInsets); + @interface UIView (LNPopupSupportPrivate) -- (void)_ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:(BOOL)layout; -- (BOOL)_ln_scrollEdgeAppearanceRequiresFadeForPopupBar:(LNPopupBar*)popupBar; +- (void)_ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:(BOOL)layout API_AVAILABLE(ios(13.0)); +- (BOOL)_ln_scrollEdgeAppearanceRequiresFadeForPopupBar:(LNPopupBar*)popupBar API_AVAILABLE(ios(13.0)); - (void)_ln_letMeKnowWhenViewInWindowHierarchy:(LNInWindowBlock)block; - (void)_ln_forgetAboutIt; - (nullable NSString*)_ln_effectGroupingIdentifierIfAvailable; +- (void)_ln_freezeInsets; + @end @interface UIView () -- (id)_lnpopup_scrollEdgeAppearance; +- (id)_lnpopup_scrollEdgeAppearance API_AVAILABLE(ios(13.0)); @end -#if TARGET_OS_MACCATALYST +@interface UITabBar () + +@property (nonatomic, getter=_ignoringLayoutDuringTransition, setter=_setIgnoringLayoutDuringTransition:) BOOL ignoringLayoutDuringTransition; + +@end @interface UIWindow (MacCatalystSupport) @@ -46,6 +54,15 @@ typedef void (^LNInWindowBlock)(dispatch_block_t); @end -#endif - NS_ASSUME_NONNULL_END + +@interface UIScrollView (LNPopupSupportPrivate) + +- (BOOL)_ln_hasHorizontalContent; +- (BOOL)_ln_hasVerticalContent; +- (BOOL)_ln_scrollingOnlyVertically; +- (BOOL)_ln_isAtTop; + +@end + +@interface _LNPopupBarBackgroundGroupNameOverride: NSObject @end diff --git a/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.m b/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.mm similarity index 63% rename from LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.m rename to LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.mm index 7858891..ba1adf6 100644 --- a/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.m +++ b/LNPopupController/LNPopupController/Private/UIView+LNPopupSupportPrivate.mm @@ -2,21 +2,28 @@ // UIView+LNPopupSupportPrivate.m // LNPopupController // -// Created by Leo Natan on 8/1/20. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2020-08-01. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "UIView+LNPopupSupportPrivate.h" #import "UIViewController+LNPopupSupportPrivate.h" #import "LNPopupController.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" #import "LNPopupBar+Private.h" #import "_LNPopupUIBarAppearanceProxy.h" #import "_LNWeakRef.h" -@import ObjectiveC; -#if TARGET_OS_MACCATALYST -@import AppKit; -#endif +#import + +@implementation _LNPopupBarBackgroundGroupNameOverride + ++ (__kindof id)defaultValue +{ + return nil; +} + +@end static const void* LNPopupAttachedPopupController = &LNPopupAttachedPopupController; static const void* LNPopupAwaitingViewInWindowHierarchyKey = &LNPopupAwaitingViewInWindowHierarchyKey; @@ -24,39 +31,21 @@ static const void* LNPopupNotifyingKey = &LNPopupNotifyingKey; static const void* LNPopupTabBarProgressKey = &LNPopupTabBarProgressKey; static const void* LNPopupBarBackgroundViewForceAnimatedKey = &LNPopupBarBackgroundViewForceAnimatedKey; -#if ! LNPopupControllerEnforceStrictClean -//backdropGroupName -static NSString* _bGN = @"YmFja2Ryb3BHcm91cE5hbWU="; -//_UINavigationBarVisualProvider -static NSString* _UINBVP = @"X1VJTmF2aWdhdGlvbkJhclZpc3VhbFByb3ZpZGVy"; -//_UINavigationBarVisualProviderLegacyIOS -static NSString* _UINBVPLI = @"X1VJTmF2aWdhdGlvbkJhclZpc3VhbFByb3ZpZGVyTGVnYWN5SU9T"; -//_UINavigationBarVisualProviderModernIOS -static NSString* _UINBVPMI = @"X1VJTmF2aWdhdGlvbkJhclZpc3VhbFByb3ZpZGVyTW9kZXJuSU9T"; -//updateBackgroundGroupName -static NSString* _uBGN = @"dXBkYXRlQmFja2dyb3VuZEdyb3VwTmFtZQ=="; -//_viewControllerForAncestor -static NSString* _vCFA = @"X3ZpZXdDb250cm9sbGVyRm9yQW5jZXN0b3I="; -//_didMoveFromWindow:toWindow: -static NSString* _dMFWtW = @"X2RpZE1vdmVGcm9tV2luZG93OnRvV2luZG93Og=="; -//_backdropViewLayerGroupName -static NSString* _bVLGN = @"X2JhY2tkcm9wVmlld0xheWVyR3JvdXBOYW1l"; -//hostWindow -static NSString* _hW = @"aG9zdFdpbmRvdw=="; -//attachedWindow -static NSString* _aW = @"YXR0YWNoZWRXaW5kb3c="; -//currentEvent -static NSString* _cE = @"Y3VycmVudEV2ZW50"; -//backgroundTransitionProgress -static NSString* _bTP = @"YmFja2dyb3VuZFRyYW5zaXRpb25Qcm9ncmVzcw=="; -//_UIBarBackground -static NSString* _UBB = @"X1VJQmFyQmFja2dyb3VuZA=="; -//transitionBackgroundViewsAnimated: -static NSString* _tBVA = @"dHJhbnNpdGlvbkJhY2tncm91bmRWaWV3c0FuaW1hdGVkOg=="; -//_backgroundView -static NSString* _bV = @"X2JhY2tncm91bmRWaWV3"; +@interface __LNPopupUIViewFrozenInsets : NSObject @end +@implementation __LNPopupUIViewFrozenInsets -#endif ++ (void)load +{ + @autoreleasepool + { + const char* encoding = method_getTypeEncoding(class_getInstanceMethod(UIView.class, @selector(needsUpdateConstraints))); + class_addMethod(self, NSSelectorFromString(LNPopupHiddenString("_safeAreaInsetsFrozen")), imp_implementationWithBlock(^ (id self, SEL _cmd) { + return YES; + }), encoding); + } +} + +@end @interface UIViewController () @@ -97,107 +86,57 @@ static NSString* _bV = @"X2JhY2tncm91bmRWaWV3"; + (void)load { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ + @autoreleasepool + { #if ! LNPopupControllerEnforceStrictClean - if(@available(iOS 13.0, *)) - { - //updateBackgroundGroupName - SEL updateBackgroundGroupNameSEL = NSSelectorFromString(_LNPopupDecodeBase64String(_uBGN)); - - id (^trampoline)(void (*)(id, SEL)) = ^ id (void (*orig)(id, SEL)){ - return ^ (id _self) { - orig(_self, updateBackgroundGroupNameSEL); - - static NSString* key = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - //backdropGroupName - key = _LNPopupDecodeBase64String(_bGN); - }); - - NSString* groupName = [_self valueForKey:key]; - if([groupName hasSuffix:@"🤡"] == NO) - { - [_self setValue:[NSString stringWithFormat:@"%@🤡", groupName] forKey:key]; - } - }; + SEL updateBackgroundGroupNameSEL = NSSelectorFromString(LNPopupHiddenString("updateBackgroundGroupName")); + + id (^trampoline)(void (*)(id, SEL)) = ^ id (void (*orig)(id, SEL)){ + return ^ (id _self) { + orig(_self, updateBackgroundGroupNameSEL); + + static NSString* groupNameKey = LNPopupHiddenString("groupName"); + static NSString* backgroundViewKey = LNPopupHiddenString("backgroundView"); + + id backgroundView = [_self valueForKey:backgroundViewKey]; + + NSString* groupName = [backgroundView valueForKey:groupNameKey]; + if([groupName hasSuffix:@"🤡"] == NO) + { + [backgroundView setValue:[NSString stringWithFormat:@"%@🤡", groupName] forKey:groupNameKey]; + } }; - - { - //_UINavigationBarVisualProvider - Class cls = NSClassFromString(_LNPopupDecodeBase64String(_UINBVP)); - Method m = class_getInstanceMethod(cls, updateBackgroundGroupNameSEL); - void (*orig)(id, SEL) = (void*)method_getImplementation(m); - method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); - } - - { - //_UINavigationBarVisualProviderLegacyIOS - Class cls = NSClassFromString(_LNPopupDecodeBase64String(_UINBVPLI)); - Method m = class_getInstanceMethod(cls, updateBackgroundGroupNameSEL); - void (*orig)(id, SEL) = (void*)method_getImplementation(m); - method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); - } - - { - //_UINavigationBarVisualProviderModernIOS - Class cls = NSClassFromString(_LNPopupDecodeBase64String(_UINBVPMI)); - Method m = class_getInstanceMethod(cls, updateBackgroundGroupNameSEL); - void (*orig)(id, SEL) = (void*)method_getImplementation(m); - method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); - } - } - else + }; + { - //updateBackgroundGroupName - SEL updateBackgroundsSEL = NSSelectorFromString(@"_updateBackgrounds"); - - id (^trampoline)(void (*)(id, SEL)) = ^ id (void (*orig)(id, SEL)){ - return ^ (id _self) { - orig(_self, updateBackgroundsSEL); - - static NSString* key = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - //groupName - key = @"backgroundView.groupName"; - }); - - NSString* groupName = [_self valueForKeyPath:key]; - if([groupName hasSuffix:@"🤡"] == NO) - { - [_self setValue:[NSString stringWithFormat:@"%@🤡", groupName] forKeyPath:key]; - } - }; - }; - - { - //_UINavigationBarVisualProvider - Class cls = NSClassFromString(_LNPopupDecodeBase64String(_UINBVP)); - Method m = class_getInstanceMethod(cls, updateBackgroundsSEL); - void (*orig)(id, SEL) = (void*)method_getImplementation(m); - method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); - } - - { - //_UINavigationBarVisualProviderLegacyIOS - Class cls = NSClassFromString(_LNPopupDecodeBase64String(_UINBVPLI)); - Method m = class_getInstanceMethod(cls, updateBackgroundsSEL); - void (*orig)(id, SEL) = (void*)method_getImplementation(m); - method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); - } - - { - //_UINavigationBarVisualProviderModernIOS - Class cls = NSClassFromString(_LNPopupDecodeBase64String(_UINBVPMI)); - Method m = class_getInstanceMethod(cls, updateBackgroundsSEL); - void (*orig)(id, SEL) = (void*)method_getImplementation(m); - method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); - } + Class cls = NSClassFromString(LNPopupHiddenString("_UINavigationBarVisualProvider")); + Method m = class_getInstanceMethod(cls, updateBackgroundGroupNameSEL); + void (*orig)(id, SEL) = reinterpret_cast(method_getImplementation(m)); + method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); } - NSString* sel = _LNPopupDecodeBase64String(_dMFWtW); + { + Class cls = NSClassFromString(LNPopupHiddenString("_UINavigationBarVisualProviderLegacyIOS")); + Method m = class_getInstanceMethod(cls, updateBackgroundGroupNameSEL); + void (*orig)(id, SEL) = reinterpret_cast(method_getImplementation(m)); + method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); + } + + { + Class cls = NSClassFromString(LNPopupHiddenString("_UINavigationBarVisualProviderModernIOS")); + Method m = class_getInstanceMethod(cls, updateBackgroundGroupNameSEL); + void (*orig)(id, SEL) = reinterpret_cast(method_getImplementation(m)); + method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); + } + + { + Class cls = NSClassFromString(LNPopupHiddenString("_UITabBarVisualProviderLegacyIOS")); + Method m = class_getInstanceMethod(cls, updateBackgroundGroupNameSEL); + void (*orig)(id, SEL) = reinterpret_cast(method_getImplementation(m)); + method_setImplementation(m, imp_implementationWithBlock(trampoline(orig))); + } + + NSString* sel = LNPopupHiddenString("_didMoveFromWindow:toWindow:"); LNSwizzleMethod(self, NSSelectorFromString(sel), @selector(_ln__dMFW:tW:)); @@ -206,7 +145,7 @@ static NSString* _bV = @"X2JhY2tncm91bmRWaWV3"; @selector(didMoveToWindow), @selector(_ln_didMoveToWindow)); #endif - }); + } } - (void)_ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:(BOOL)layout @@ -242,7 +181,7 @@ static NSString* _bV = @"X2JhY2tncm91bmRWaWV3"; #endif LNAlwaysInline -static void _LNNotify(UIView* self, NSMutableArray* waiting) +void _LNNotify(UIView* self, NSMutableArray* waiting) { if(waiting.count == 0) { @@ -307,11 +246,7 @@ static void _LNNotify(UIView* self, NSMutableArray* waiting) - (NSString*)_ln_effectGroupingIdentifierIfAvailable { #if ! LNPopupControllerEnforceStrictClean - static NSString* key = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - key = _LNPopupDecodeBase64String(_bVLGN); - }); + static NSString* key = LNPopupHiddenString("_backdropViewLayerGroupName"); if([self respondsToSelector:NSSelectorFromString(key)]) { @@ -326,9 +261,63 @@ static void _LNNotify(UIView* self, NSMutableArray* waiting) #endif } +- (void)_ln_freezeInsets +{ + LNDynamicallySubclass(self, __LNPopupUIViewFrozenInsets.class); +} + @end -#if TARGET_OS_MACCATALYST +#if ! LNPopupControllerEnforceStrictClean +@interface UIWindow (ScrollToTopFix) @end +@implementation UIWindow (ScrollToTopFix) + ++ (void)load +{ + @autoreleasepool + { + NSString* selName = LNPopupHiddenString("_registeredScrollToTopViews"); + LNSwizzleMethod(self, + NSSelectorFromString(selName), + @selector(_ln_rSTTV)); + } +} + +//_registeredScrollToTopViews +- (NSArray*)_ln_rSTTV +{ + NSArray* rv = [self _ln_rSTTV]; + NSMutableArray* popupRV = [NSMutableArray new]; + + static NSString* vCFA = LNPopupHiddenString("_viewControllerForAncestor"); + + for(UIView* scrollToTopCandidate in rv) + { + UIViewController* vc = [scrollToTopCandidate valueForKey:vCFA]; + + if(vc == nil) + { + continue; + } + + BOOL fromPopup = vc._isContainedInOpenPopupController; + if(fromPopup) + { + [popupRV addObject:scrollToTopCandidate]; + } + } + + if(popupRV.count > 0) + { + return popupRV; + } + + return rv; +} + +@end + +#endif @implementation UIWindow (MacCatalystSupport) @@ -338,18 +327,11 @@ static void _LNNotify(UIView* self, NSMutableArray* waiting) return nil; #else //hostWindow - static NSString* hW; + static NSString* hW = LNPopupHiddenString("hostWindow"); //attachedWindow - static NSString* aW; + static NSString* aW = LNPopupHiddenString("attachedWindow"); //currentEvent - static NSString* cE; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - hW = _LNPopupDecodeBase64String(_hW); - aW = _LNPopupDecodeBase64String(_aW); - cE = _LNPopupDecodeBase64String(_cE); - }); + static NSString* cE = LNPopupHiddenString("currentEvent"); //Obtain the actual NSWindow object id hostingWindow = [self valueForKey:hW]; @@ -365,9 +347,6 @@ static void _LNNotify(UIView* self, NSMutableArray* waiting) @end - -#endif - LNAlwaysInline BOOL _LNBottomBarIsInPopupPresentation(NSObject* self) { @@ -403,14 +382,11 @@ id _LNPopupReturnScrollEdgeAppearanceOrStandardAppearance(id self, SEL standardA #pragma clang diagnostic pop } -static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPopupBar* popupBar) API_AVAILABLE(ios(13.0)) +API_AVAILABLE(ios(13.0)) +static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPopupBar* popupBar) { //backgroundTransitionProgress - static NSString* bTP = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - bTP = _LNPopupDecodeBase64String(_bTP); - }); + static NSString* bTP = LNPopupHiddenString("backgroundTransitionProgress"); BOOL isAtScrollEdge = [[bottomBar valueForKey:bTP] doubleValue] > 0; @@ -433,6 +409,7 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop { if(@available(iOS 15.0, *)) { + LNSwizzleMethod(self, @selector(layoutSubviews), @selector(_ln_layoutSubviews)); #if ! LNPopupControllerEnforceStrictClean LNSwizzleMethod(self, @selector(standardAppearance), @selector(_lnpopup_standardAppearance)); LNSwizzleMethod(self, @selector(compactAppearance), @selector(_lnpopup_compactAppearance)); @@ -445,6 +422,13 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop } } +- (void)_ln_layoutSubviews +{ + [self _ln_layoutSubviews]; + + [self._ln_attachedPopupController _configurePopupBarFromBottomBarModifyingGroupingIdentifier:NO]; +} + - (void)_ln_triggerBarAppearanceRefreshIfNeededTriggeringLayout:(BOOL)layout { if(@available(iOS 15.0, *)) @@ -459,7 +443,7 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop } } -- (BOOL)_ln_scrollEdgeAppearanceRequiresFadeForPopupBar:(LNPopupBar*)popupBar API_AVAILABLE(ios(13.0)) +- (BOOL)_ln_scrollEdgeAppearanceRequiresFadeForPopupBar:(LNPopupBar*)popupBar { return __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(self, popupBar); } @@ -590,13 +574,26 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop @end +static const void* LNPopupIgnoringLayoutDuringTransition = &LNPopupIgnoringLayoutDuringTransition; + @interface UITabBar (ScrollEdgeSupport) @end @implementation UITabBar (ScrollEdgeSupport) +- (BOOL)_ignoringLayoutDuringTransition +{ + return [objc_getAssociatedObject(self, LNPopupIgnoringLayoutDuringTransition) boolValue]; +} + +- (void)_setIgnoringLayoutDuringTransition:(BOOL)ignoringLayoutDuringTransition +{ + objc_setAssociatedObject(self, LNPopupIgnoringLayoutDuringTransition, @(ignoringLayoutDuringTransition), OBJC_ASSOCIATION_RETAIN); +} + + (void)load { @autoreleasepool { + LNSwizzleMethod(self, @selector(setFrame:), @selector(_ln_setFrame:)); LNSwizzleMethod(self, @selector(layoutSubviews), @selector(_ln_layoutSubviews)); LNSwizzleMethod(self, @selector(setSelectedItem:), @selector(_ln_setSelectedItem:)); @@ -612,10 +609,10 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop #if ! LNPopupControllerEnforceStrictClean if(@available(iOS 17.0, *)) { - Class cls = NSClassFromString(_LNPopupDecodeBase64String(_UBB)); - SEL sel = NSSelectorFromString(_LNPopupDecodeBase64String(_tBVA)); + Class cls = NSClassFromString(LNPopupHiddenString("_UIBarBackground")); + SEL sel = NSSelectorFromString(LNPopupHiddenString("transitionBackgroundViewsAnimated:")); Method m = class_getInstanceMethod(cls, sel); - void (*orig)(id, SEL, BOOL) = (void*)method_getImplementation(m); + void (*orig)(id, SEL, BOOL) = reinterpret_cast(method_getImplementation(m)); method_setImplementation(m, imp_implementationWithBlock(^(id _self, BOOL animated) { if([objc_getAssociatedObject(_self, LNPopupBarBackgroundViewForceAnimatedKey) boolValue] == YES) { @@ -629,6 +626,14 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop } } +- (void)_ln_setFrame:(CGRect)frame +{ + if(self._ignoringLayoutDuringTransition == NO) + { + [self _ln_setFrame:frame]; + } +} + - (void)_ln_layoutSubviews { [self _ln_layoutSubviews]; @@ -656,7 +661,9 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop if(@available(iOS 15.0, *)) { #if ! LNPopupControllerEnforceStrictClean - backgroundView = [self valueForKey:_LNPopupDecodeBase64String(_bV)]; + static NSString* backgroundViewKey = LNPopupHiddenString("_backgroundView"); + + backgroundView = [self valueForKey:backgroundViewKey]; if(backgroundView != nil) { objc_setAssociatedObject(backgroundView, LNPopupBarBackgroundViewForceAnimatedKey, @(YES), OBJC_ASSOCIATION_RETAIN_NONATOMIC); @@ -686,12 +693,12 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop } } -- (BOOL)_ln_scrollEdgeAppearanceRequiresFadeForPopupBar:(LNPopupBar*)popupBar API_AVAILABLE(ios(13.0)) +- (BOOL)_ln_scrollEdgeAppearanceRequiresFadeForPopupBar:(LNPopupBar*)popupBar { return __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(self, popupBar); } -- (UITabBarAppearance *)_lnpopup_scrollEdgeAppearance API_AVAILABLE(ios(13.0)) +- (UITabBarAppearance *)_lnpopup_scrollEdgeAppearance { return _LNPopupReturnScrollEdgeAppearanceOrStandardAppearance(self, @selector(standardAppearance), @selector(_lnpopup_scrollEdgeAppearance)); } @@ -723,3 +730,115 @@ static BOOL __ln_scrollEdgeAppearanceRequiresFadeForPopupBar(id bottomBar, LNPop } @end + +@implementation UIScrollView (LNPopupSupportPrivate) + +static NSString* __ln_queueingScrollViewClassPrefix = LNPopupHiddenString("Queu"); + +- (CGRect)_ln_adjustedBounds +{ + if([NSStringFromClass(self.class) containsString:__ln_queueingScrollViewClassPrefix]) + { + return self.bounds; + } + else + { + return UIEdgeInsetsInsetRect(self.bounds, self.adjustedContentInset); + } +} + +- (BOOL)_ln_hasHorizontalContent +{ + BOOL rv = self.contentSize.width > self._ln_adjustedBounds.size.width; + +// NSLog(@"_ln_hasHorizontalContent: %@ contentSize: %@ adjustedBounds: %@", @(rv), @(self.contentSize), @(self._ln_adjustedBounds)); + + return rv; +} + +- (BOOL)_ln_hasVerticalContent +{ + BOOL rv = self.contentSize.height > self._ln_adjustedBounds.size.height; + +// NSLog(@"_ln_hasVerticalContent: %@ contentSize: %@ adjustedBounds: %@ ajustedInsets: %@", @(rv), @(self.contentSize), @(self._ln_adjustedBounds), @(self.adjustedContentInset)); + + return rv; +} + +- (BOOL)_ln_scrollingOnlyVertically +{ + return self._ln_hasHorizontalContent == NO || [self.panGestureRecognizer translationInView:self].x == 0; +} + +- (BOOL)_ln_isAtTop +{ + if([NSStringFromClass(self.class) containsString:__ln_queueingScrollViewClassPrefix]) + { + if(self._ln_hasVerticalContent) + { + static SEL viewBeforeViewSEL = NSSelectorFromString(LNPopupHiddenString("_viewBeforeView:")); + static id (*viewBeforeView)(id, SEL, id) = reinterpret_cast(method_getImplementation(class_getInstanceMethod(self.class, viewBeforeViewSEL))); + static SEL visibleViewSEL = NSSelectorFromString(LNPopupHiddenString("visibleView")); + static id (*visibleView)(id, SEL) = reinterpret_cast(method_getImplementation(class_getInstanceMethod(self.class, visibleViewSEL))); + + id visible = visibleView(self, visibleViewSEL); + return visible == nil || viewBeforeView(self, viewBeforeViewSEL, visible) == nil; + } + else + { + return YES; + } + } + + return self.contentOffset.y <= - (self.adjustedContentInset.top); +} + +@end + +UIEdgeInsets _LNEdgeInsetsFromDirectionalEdgeInsets(UIView* view, NSDirectionalEdgeInsets edgeInsets) +{ + if(view.effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) + { + return UIEdgeInsetsMake(edgeInsets.top, edgeInsets.leading, edgeInsets.bottom, edgeInsets.trailing); + } + else + { + return UIEdgeInsetsMake(edgeInsets.top, edgeInsets.trailing, edgeInsets.bottom, edgeInsets.leading); + } +} + +#if ! LNPopupControllerEnforceStrictClean + +@interface UIVisualEffectView (LNPopupSupportPrivate) @end +@implementation UIVisualEffectView (LNPopupSupportPrivate) + ++ (void)load +{ + @autoreleasepool + { + if(@available(iOS 17.0, *)) + { + NSString* selName = LNPopupHiddenString("_setGroupName:"); + LNSwizzleMethod(self, + NSSelectorFromString(selName), + @selector(_ln_sGN:)); + } + } +} + +//_setGroupName: +- (void)_ln_sGN:(NSString*)name API_AVAILABLE(ios(17.0)) +{ + NSString* override = [self.traitCollection objectForTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + if(override != nil) + { + [self _ln_sGN:override]; + return; + } + + [self _ln_sGN:name]; +} + +@end + +#endif diff --git a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.m b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.mm similarity index 68% rename from LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.m rename to LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.mm index e79812b..b2049ee 100644 --- a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.m +++ b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupport.mm @@ -2,8 +2,8 @@ // UIViewController+LNPopupSupport.m // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "UIViewController+LNPopupSupportPrivate.h" @@ -11,8 +11,10 @@ #import "_LNWeakRef.h" #import "UIView+LNPopupSupportPrivate.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" #import "LNMath.h" -@import ObjectiveC; +#import "LNPopupBar+Private.h" +#import static const void* _LNPopupItemKey = &_LNPopupItemKey; static const void* _LNPopupControllerKey = &_LNPopupControllerKey; @@ -25,31 +27,26 @@ static const void* _LNPopupShouldExtendUnderSafeAreaKey = &_LNPopupShouldExtendU const double LNSnapPercentDefault = 0.32; +extern "C" { +extern LNPopupInteractionStyle _LNPopupResolveInteractionStyleFromInteractionStyle(LNPopupInteractionStyle style); +} + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincomplete-implementation" @implementation UIViewController (LNPopupSupportPrivate) -@dynamic ln_popupController, popupPresentationContainerViewController, popupContentViewController, bottomBarSupport; +@dynamic ln_popupController, popupPresentationContainerViewController, popupContentViewController, bottomBarSupport, ln_discoveredTransitionView; @end #pragma clang diagnostic pop -#if ! LNPopupControllerEnforceStrictClean -//_existingPresentationControllerImmediate:effective: -static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlckltbWVkaWF0ZTplZmZlY3RpdmU6"; -#endif - @implementation UIViewController (LNPopupSupport) - (UIPresentationController*)nonMemoryLeakingPresentationController { #if ! LNPopupControllerEnforceStrictClean - static NSString* sel = nil; - static id (*nonLeakingPresentationController)(id, SEL, BOOL, BOOL) = (id(*)(id, SEL, BOOL, BOOL))objc_msgSend; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sel = _LNPopupDecodeBase64String(ePCIEBase64); - }); + static NSString* sel = LNPopupHiddenString("_existingPresentationControllerImmediate:effective:");; + static id (*nonLeakingPresentationController)(id, SEL, BOOL, BOOL) = reinterpret_cast(objc_msgSend); return nonLeakingPresentationController(self, NSSelectorFromString(sel), NO, NO); #else @@ -68,8 +65,15 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc if(self.view.window == nil) { + __weak __typeof(self) weakSelf = self; [self.view _ln_letMeKnowWhenViewInWindowHierarchy:^(dispatch_block_t completionBlockInWindow) { - [self presentPopupBarWithContentViewController:controller openPopup:openPopup animated:NO completion:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(strongSelf == nil) + { + return; + } + + [strongSelf presentPopupBarWithContentViewController:controller openPopup:openPopup animated:NO completion:^{ if(completionBlock) { completionBlock(); } completionBlockInWindow(); }]; @@ -100,8 +104,15 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc { if(self.view.window == nil) { + __weak __typeof(self) weakSelf = self; [self.view _ln_letMeKnowWhenViewInWindowHierarchy:^(dispatch_block_t completionBlockInWindow) { - [self openPopupAnimated:NO completion:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(strongSelf == nil) + { + return; + } + + [strongSelf openPopupAnimated:NO completion:^{ if(completionBlock) { completionBlock(); } completionBlockInWindow(); }]; @@ -117,8 +128,15 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc { if(self.view.window == nil) { + __weak __typeof(self) weakSelf = self; [self.view _ln_letMeKnowWhenViewInWindowHierarchy:^(dispatch_block_t completionBlockInWindow) { - [self closePopupAnimated:NO completion:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(strongSelf == nil) + { + return; + } + + [strongSelf closePopupAnimated:NO completion:^{ if(completionBlock) { completionBlock(); } completionBlockInWindow(); }]; @@ -134,8 +152,15 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc { if(self.view.window == nil) { + __weak __typeof(self) weakSelf = self; [self.view _ln_letMeKnowWhenViewInWindowHierarchy:^(dispatch_block_t completionBlockInWindow) { - [self dismissPopupBarAnimated:NO completion:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(strongSelf == nil) + { + return; + } + + [strongSelf dismissPopupBarAnimated:NO completion:^{ if(completionBlock) { completionBlock(); } completionBlockInWindow(); }]; @@ -189,6 +214,16 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc return [self.parentViewController _isContainedInPopupController]; } +- (BOOL)_isContainedInOpenPopupController +{ + if(self.popupPresentationContainerViewController != nil) + { + return self.popupPresentationContainerViewController._ln_popupController_nocreate.popupControllerPublicState == LNPopupPresentationStateOpen; + } + + return [self.parentViewController _isContainedInOpenPopupController]; +} + - (BOOL)_isContainedInPopupControllerOrDeallocated { if(objc_getAssociatedObject(self, _LNPopupPresentationContainerViewControllerKey) != nil) @@ -243,6 +278,16 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc return NO; } +- (nullable UIView*)viewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState +{ + return self._ln_discoveredTransitionView; +} + +- (nullable UIView*)_ln_transitionViewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState view:(out id _Nonnull __strong * _Nonnull)outView +{ + return nil; +} + - (void)viewWillMoveToPopupContainerContentView:(LNPopupContentView *)popupContentView { @@ -268,6 +313,11 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc return (LNPopupInteractionStyle)[objc_getAssociatedObject(self, _LNPopupInteractionStyleKey) unsignedIntegerValue]; } +- (LNPopupInteractionStyle)effectivePopupInteractionStyle +{ + return _LNPopupResolveInteractionStyleFromInteractionStyle((LNPopupInteractionStyle)[objc_getAssociatedObject(self, _LNPopupInteractionStyleKey) unsignedIntegerValue]); +} + - (void)setPopupInteractionStyle:(LNPopupInteractionStyle)popupInteractionStyle { objc_setAssociatedObject(self, _LNPopupInteractionStyleKey, @(popupInteractionStyle), OBJC_ASSOCIATION_RETAIN_NONATOMIC); @@ -310,6 +360,28 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc self._ln_popupController.wantsFeedbackGeneration = allowPopupHapticFeedbackGeneration; } +static const void* _LNPopupContentControllerDiscoveredTransitionView = &_LNPopupContentControllerDiscoveredTransitionView; + +- (void)_ln_setDiscoveredTransitionView:(LNPopupImageView *)ln_discoveredShadowedImageView +{ + id objToSet = nil; + if(ln_discoveredShadowedImageView != nil) + { + objToSet = [_LNWeakRef refWithObject:ln_discoveredShadowedImageView]; + } + objc_setAssociatedObject(self, _LNPopupContentControllerDiscoveredTransitionView, objToSet, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (LNPopupImageView *)_ln_discoveredTransitionView +{ + _LNWeakRef* rv = objc_getAssociatedObject(self, _LNPopupContentControllerDiscoveredTransitionView); + if(rv != nil && rv.object == nil) + { + [self _ln_setDiscoveredTransitionView:nil]; + } + return rv.object; +} + @end @implementation UIViewController (LNCustomContainerPopupSupport) @@ -374,9 +446,37 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc return CGRectZero; } +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle +{ + if(barStyle != LNPopupBarStyleFloating /*|| UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone*/) + { + return 0.0; + } + + id dockingView = self.bottomDockingViewForPopupBar; + + if(dockingView != nil && ([dockingView isKindOfClass:UIToolbar.class] || [dockingView isKindOfClass:UITabBar.class]) == NO) + { + //User docking view, do not offset. + return 0.0; + } + + if(LNPopupBar.isCatalystApp) + { + return -7.0; + } + + if(self.view.window.safeAreaInsets.bottom == 0) + { + return -4.0; + } + + return self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular ? 7.0 : 0.0; +} + - (CGRect)defaultFrameForBottomDockingView_internal { - CGFloat safeAreaAddition = self.view.safeAreaInsets.bottom - _LNPopupSafeAreas(self).bottom; + CGFloat safeAreaAddition = self.view.safeAreaInsets.bottom - _LNPopupSafeAreaInsets(self).bottom; if(self.presentingViewController != nil && [NSStringFromClass(self.nonMemoryLeakingPresentationController.class) containsString:@"Preview"]) { @@ -386,9 +486,13 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc return CGRectMake(0, self.view.bounds.size.height - safeAreaAddition, self.view.bounds.size.width, safeAreaAddition); } -- (CGRect)defaultFrameForBottomDockingView_internalOrDeveloper +- (CGRect)_defaultFrameForBottomDockingViewForPopupBar:(LNPopupBar*)popupBar { - return [self bottomDockingViewForPopupBar] != nil ? [self defaultFrameForBottomDockingView] : [self defaultFrameForBottomDockingView_internal]; + LNPopupBarStyle barStyle = popupBar != nil ? popupBar.resolvedStyle : _LNPopupResolveBarStyleFromBarStyle(LNPopupBarStyleDefault); + + CGRect rv = [self bottomDockingViewForPopupBar] != nil ? [self defaultFrameForBottomDockingView] : [self defaultFrameForBottomDockingView_internal]; + rv.origin.y += [self _ln_popupOffsetForPopupBarStyle:barStyle]; + return rv; } - (BOOL)shouldExtendPopupBarUnderSafeArea @@ -428,6 +532,16 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc return [self.topViewController positionPopupCloseButton:popupCloseButton]; } +- (nullable UIView*)viewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState +{ + return [self.topViewController viewForPopupTransitionFromPresentationState:fromState toPresentationState:toState]; +} + +- (nullable UIView*)_ln_transitionViewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState view:(out id _Nonnull __strong * _Nonnull)outView +{ + return [self.topViewController _ln_transitionViewForPopupTransitionFromPresentationState:fromState toPresentationState:toState view:outView]; +} + @end @implementation UITabBarController (LNPopupSupport) @@ -437,4 +551,14 @@ static NSString* const ePCIEBase64 = @"X2V4aXN0aW5nUHJlc2VudGF0aW9uQ29udHJvbGxlc return [self.selectedViewController positionPopupCloseButton:popupCloseButton]; } +- (nullable UIView*)viewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState +{ + return [self.selectedViewController viewForPopupTransitionFromPresentationState:fromState toPresentationState:toState]; +} + +- (nullable UIView*)_ln_transitionViewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState view:(out id _Nonnull __strong * _Nonnull)outView +{ + return [self.selectedViewController _ln_transitionViewForPopupTransitionFromPresentationState:fromState toPresentationState:toState view:outView]; +} + @end diff --git a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h index ba58453..b123500 100644 --- a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h +++ b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.h @@ -2,13 +2,15 @@ // UIViewController+LNPopupSupportPrivate.h // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import #import "_LNPopupBarBackgroundView.h" +CF_EXTERN_C_BEGIN + @class LNPopupController; NS_ASSUME_NONNULL_BEGIN @@ -26,13 +28,15 @@ static inline __attribute__((always_inline)) UIEdgeInsets __LNEdgeInsetsSum(UIEd extern BOOL __ln_popup_suppressViewControllerLifecycle; -UIEdgeInsets _LNPopupSafeAreas(id self); +UIEdgeInsets _LNPopupSafeAreaInsets(id self); void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller, BOOL layout, UIEdgeInsets popupEdgeInsets); @interface _LNPopupBottomBarSupport : UIView @end @interface UIViewController (LNPopupSupportPrivate) +- (void)_ln_updateSafeAreaInsets; + - (BOOL)_ln_shouldDisplayBottomShadowViewDuringTransition; - (BOOL)_ln_reallyShouldExtendPopupBarUnderSafeArea; @@ -51,6 +55,7 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller - (nullable _LNPopupBottomBarSupport *)_ln_bottomBarSupport_nocreate; - (BOOL)_isContainedInPopupController; +- (BOOL)_isContainedInOpenPopupController; - (BOOL)_isContainedInPopupControllerOrDeallocated; - (BOOL)_ignoringLayoutDuringTransition; @@ -58,20 +63,32 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller - (nullable UIView *)bottomDockingViewForPopup_nocreateOrDeveloper; - (nonnull UIView *)bottomDockingViewForPopup_internalOrDeveloper; +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle; + - (CGRect)defaultFrameForBottomDockingView_internal; -- (CGRect)defaultFrameForBottomDockingView_internalOrDeveloper; +- (CGRect)_defaultFrameForBottomDockingViewForPopupBar:(LNPopupBar*)LNPopupBar; - (_LNPopupBarBackgroundView*)_ln_bottomBarExtension_nocreate; - (_LNPopupBarBackgroundView*)_ln_bottomBarExtension; - (void)_userFacing_viewWillAppear:(BOOL)animated; -- (void)_userFacing_viewIsAppearing:(BOOL)animated API_AVAILABLE(ios(13.0)); +- (void)_userFacing_viewIsAppearing:(BOOL)animated; - (void)_userFacing_viewDidAppear:(BOOL)animated; - (void)_userFacing_viewWillDisappear:(BOOL)animated; - (void)_userFacing_viewDidDisappear:(BOOL)animated; +- (BOOL)_ln_isObjectFromSwiftUI; + +- (BOOL)_ln_shouldPopupContentAnyFadeForTransition; +- (BOOL)_ln_shouldPopupContentViewFadeForTransition; +@property (nullable, nonatomic, weak, setter=_ln_setDiscoveredTransitionView:, getter=_ln_discoveredTransitionView) LNPopupImageView* ln_discoveredTransitionView; + +- (nullable UIView*)_ln_transitionViewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState view:(out id _Nonnull __strong * _Nonnull)outView; + @end @interface _LN_UIViewController_AppearanceControl : UIViewController @end NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END diff --git a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.m b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.mm similarity index 66% rename from LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.m rename to LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.mm index aef720d..ea0ba20 100644 --- a/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.m +++ b/LNPopupController/LNPopupController/Private/UIViewController+LNPopupSupportPrivate.mm @@ -2,17 +2,18 @@ // UIViewController+LNPopupSupportPrivate.m // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "UIViewController+LNPopupSupportPrivate.h" #import "LNPopupController.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" #import "UIView+LNPopupSupportPrivate.h" -@import ObjectiveC; -@import Darwin; +#import +#import static const void* LNToolbarHiddenBeforeTransition = &LNToolbarHiddenBeforeTransition; static const void* LNPopupAdjustingInsets = &LNPopupAdjustingInsets; @@ -38,6 +39,8 @@ BOOL __ln_popup_suppressViewControllerLifecycle = NO; @interface _LNPopupBarExtensionView : _LNPopupBarBackgroundView @end @implementation _LNPopupBarExtensionView +#if DEBUG + - (void)didMoveToSuperview { [super didMoveToSuperview]; @@ -48,6 +51,8 @@ BOOL __ln_popup_suppressViewControllerLifecycle = NO; [super setAlpha:alpha]; } +#endif + @end @interface NSObject () @@ -57,41 +62,6 @@ BOOL __ln_popup_suppressViewControllerLifecycle = NO; @end #ifndef LNPopupControllerEnforceStrictClean -//_hideBarWithTransition:isExplicit:duration: -static NSString* const hBWTiEDBase64 = @"X2hpZGVCYXJXaXRoVHJhbnNpdGlvbjppc0V4cGxpY2l0OmR1cmF0aW9uOg=="; -//_showBarWithTransition:isExplicit:duration: -static NSString* const sBWTiEDBase64 = @"X3Nob3dCYXJXaXRoVHJhbnNpdGlvbjppc0V4cGxpY2l0OmR1cmF0aW9uOg=="; -//_setToolbarHidden:edge:duration: -static NSString* const sTHedBase64 = @"X3NldFRvb2xiYXJIaWRkZW46ZWRnZTpkdXJhdGlvbjo="; -//_viewControllerUnderlapsStatusBar -static NSString* const vCUSBBase64 = @"X3ZpZXdDb250cm9sbGVyVW5kZXJsYXBzU3RhdHVzQmFy"; -//_hideShowNavigationBarDidStop:finished:context: -static NSString* const hSNBDSfcBase64 = @"X2hpZGVTaG93TmF2aWdhdGlvbkJhckRpZFN0b3A6ZmluaXNoZWQ6Y29udGV4dDo="; -//_viewSafeAreaInsetsFromScene -static NSString* const vSAIFSBase64 = @"X3ZpZXdTYWZlQXJlYUluc2V0c0Zyb21TY2VuZQ=="; -//_updateLayoutForStatusBarAndInterfaceOrientation -static NSString* const uLFSBAIO = @"X3VwZGF0ZUxheW91dEZvclN0YXR1c0JhckFuZEludGVyZmFjZU9yaWVudGF0aW9u"; -//_updateContentOverlayInsetsFromParentIfNecessary -static NSString* const uCOIFPIN = @"X3VwZGF0ZUNvbnRlbnRPdmVybGF5SW5zZXRzRnJvbVBhcmVudElmTmVjZXNzYXJ5"; -//_accessibilitySpeakThisViewController -static NSString* const aSTVC = @"X2FjY2Vzc2liaWxpdHlTcGVha1RoaXNWaWV3Q29udHJvbGxlcg=="; -//setParentViewController: -static NSString* const sPVC = @"c2V0UGFyZW50Vmlld0NvbnRyb2xsZXI6"; -//UIViewControllerAccessibility -static NSString* const uiVCA = @"VUlWaWV3Q29udHJvbGxlckFjY2Vzc2liaWxpdHk="; -//UINavigationControllerAccessibility -static NSString* const uiNVCA = @"VUlOYXZpZ2F0aW9uQ29udHJvbGxlckFjY2Vzc2liaWxpdHk="; -//UITabBarControllerAccessibility -static NSString* const uiTBCA = @"VUlUYWJCYXJDb250cm9sbGVyQWNjZXNzaWJpbGl0eQ=="; -//_prepareTabBar -static NSString* const pTBBase64 = @"X3ByZXBhcmVUYWJCYXI="; - -//_setContentOverlayInsets:andLeftMargin:rightMargin: -static NSString* const sCOIaLMrM = @"X3NldENvbnRlbnRPdmVybGF5SW5zZXRzOmFuZExlZnRNYXJnaW46cmlnaHRNYXJnaW46"; -//_contentMargin -static NSString* const cM = @"X2NvbnRlbnRNYXJnaW4="; -//_setContentMargin: -static NSString* const sCM = @"X3NldENvbnRlbnRNYXJnaW46"; //_accessibilitySpeakThisViewController static UIViewController* (*__orig_uiVCA_aSTVC)(id, SEL); @@ -100,6 +70,19 @@ static UIViewController* (*__orig_uiTBCA_aSTVC)(id, SEL); #endif +static NSTimeInterval __ln_durationForTransition(UIViewController* vc, NSUInteger transition) +{ +#ifndef LNPopupControllerEnforceStrictClean + //durationForTransition: + static SEL dFT = NSSelectorFromString(LNPopupHiddenString("durationForTransition:")); + static NSTimeInterval (*specialized_objc_msgSend)(id, SEL, NSUInteger) = reinterpret_cast(objc_msgSend); + + return specialized_objc_msgSend(vc, dFT, transition); +#else + return 0.5; +#endif +} + /** A helper view for view controllers without real bottom bars. */ @@ -132,25 +115,25 @@ static void __accessibilityBundleLoadHandler(void) return; } - NSString* selName = _LNPopupDecodeBase64String(aSTVC); + NSString* selName = LNPopupHiddenString("_accessibilitySpeakThisViewController"); //UIViewControllerAccessibility //_accessibilitySpeakThisViewController - NSString* clsName = _LNPopupDecodeBase64String(uiVCA); + NSString* clsName = LNPopupHiddenString("UIViewControllerAccessibility"); Method m1 = class_getInstanceMethod(NSClassFromString(clsName), NSSelectorFromString(selName)); - __orig_uiVCA_aSTVC = (void*)method_getImplementation(m1); + __orig_uiVCA_aSTVC = reinterpret_cast(method_getImplementation(m1)); Method m2 = class_getInstanceMethod([UIViewController class], NSSelectorFromString(@"_aSTVC")); method_exchangeImplementations(m1, m2); - clsName = _LNPopupDecodeBase64String(uiNVCA); + clsName = LNPopupHiddenString("UINavigationControllerAccessibility"); m1 = class_getInstanceMethod(NSClassFromString(clsName), NSSelectorFromString(selName)); - __orig_uiNVCA_aSTVC = (void*)method_getImplementation(m1); + __orig_uiNVCA_aSTVC = reinterpret_cast(method_getImplementation(m1)); m2 = class_getInstanceMethod([UINavigationController class], NSSelectorFromString(@"_aSTVC")); method_exchangeImplementations(m1, m2); - clsName = _LNPopupDecodeBase64String(uiTBCA); + clsName = LNPopupHiddenString("UITabBarControllerAccessibility"); m1 = class_getInstanceMethod(NSClassFromString(clsName), NSSelectorFromString(selName)); - __orig_uiTBCA_aSTVC = (void*)method_getImplementation(m1); + __orig_uiTBCA_aSTVC = reinterpret_cast(method_getImplementation(m1)); m2 = class_getInstanceMethod([UITabBarController class], NSSelectorFromString(@"_aSTVC")); method_exchangeImplementations(m1, m2); @@ -162,6 +145,16 @@ static void __accessibilityBundleLoadHandler(void) #pragma mark - UIViewController +BOOL __ln_alreadyInHideShowBar = NO; +UIRectEdge __ln_hideBarEdge = UIRectEdgeNone; + +#if __has_include() +#define HAS_SWIFT_UI 1 +CF_EXTERN_C_BEGIN +extern void __ln_doNotCall__fixUIHostingViewHitTest(void); +CF_EXTERN_C_END +#endif + @interface UIViewController (LNPopupLayout) @end @implementation UIViewController (LNPopupLayout) @@ -171,6 +164,13 @@ static void __accessibilityBundleLoadHandler(void) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ +#if HAS_SWIFT_UI + if(@available(iOS 13.0, *)) + { + __ln_doNotCall__fixUIHostingViewHitTest(); + } +#endif + __LNPopupBuggyAdditionalSafeAreaClasses = [NSSet setWithObjects:UINavigationController.class, UITabBarController.class, nil]; if(@available(iOS 13.0, *)) @@ -216,6 +216,10 @@ static void __accessibilityBundleLoadHandler(void) @selector(setNeedsStatusBarAppearanceUpdate), @selector(_ln_setNeedsStatusBarAppearanceUpdate)); + LNSwizzleMethod(self, + @selector(setNeedsUpdateOfHomeIndicatorAutoHidden), + @selector(_ln_setNeedsUpdateOfHomeIndicatorAutoHidden)); + LNSwizzleMethod(self, @selector(childViewControllerForStatusBarStyle), @selector(_ln_childViewControllerForStatusBarStyle)); @@ -224,6 +228,10 @@ static void __accessibilityBundleLoadHandler(void) @selector(childViewControllerForStatusBarHidden), @selector(_ln_childViewControllerForStatusBarHidden)); + LNSwizzleMethod(self, + @selector(childViewControllerForHomeIndicatorAutoHidden), + @selector(_ln_childViewControllerForHomeIndicatorAutoHidden)); + LNSwizzleMethod(self, @selector(viewWillTransitionToSize:withTransitionCoordinator:), @selector(_ln_viewWillTransitionToSize:withTransitionCoordinator:)); @@ -237,22 +245,19 @@ static void __accessibilityBundleLoadHandler(void) @selector(_ln_presentViewController:animated:completion:)); #ifndef LNPopupControllerEnforceStrictClean - //_viewControllerUnderlapsStatusBar - NSString* selName = _LNPopupDecodeBase64String(vCUSBBase64); + NSString* selName = LNPopupHiddenString("_viewControllerUnderlapsStatusBar"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_vCUSB)); - //_updateLayoutForStatusBarAndInterfaceOrientation - selName = _LNPopupDecodeBase64String(uLFSBAIO); + selName = LNPopupHiddenString("_updateLayoutForStatusBarAndInterfaceOrientation"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_uLFSBAIO)); if(@available(iOS 15.0, *)) { - //_updateContentOverlayInsetsFromParentIfNecessary - selName = _LNPopupDecodeBase64String(uCOIFPIN); + selName = LNPopupHiddenString("_updateContentOverlayInsetsFromParentIfNecessary"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_uCOIFPIN)); @@ -261,15 +266,13 @@ static void __accessibilityBundleLoadHandler(void) } else { - //_viewSafeAreaInsetsFromScene - selName = _LNPopupDecodeBase64String(vSAIFSBase64); + selName = LNPopupHiddenString("_viewSafeAreaInsetsFromScene"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_vSAIFS)); } - //setParentViewController: - selName = _LNPopupDecodeBase64String(sPVC); + selName = LNPopupHiddenString("setParentViewController:"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_ln_sPVC:)); @@ -278,6 +281,16 @@ static void __accessibilityBundleLoadHandler(void) } } +- (void)_ln_updateSafeAreaInsets +{ +#ifndef LNPopupControllerEnforceStrictClean + static SEL sel = NSSelectorFromString(LNPopupHiddenString("_updateContentOverlayInsetsForSelfAndChildren")); + static void(*objc_msgSend_uCOIFSAC)(id, SEL) = reinterpret_cast(objc_msgSend); + + objc_msgSend_uCOIFSAC(self, sel); +#endif +} + - (BOOL)_ln_isModalInPresentation { if(self._ln_popupController_nocreate.popupControllerInternalState >= _LNPopupPresentationStateTransitioning) @@ -288,13 +301,38 @@ static void __accessibilityBundleLoadHandler(void) return [self _ln_isModalInPresentation]; } -- (void)_ln_popup_setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)overrideUserInterfaceStyle API_AVAILABLE(ios(13.0)) +- (BOOL)_ln_isObjectFromSwiftUI +{ + static NSString* key = LNPopupHiddenString("_isFromSwiftUI"); + return [self.class respondsToSelector:NSSelectorFromString(key)] && [[self.class valueForKey:key] boolValue]; +} + +- (BOOL)_ln_shouldPopupContentAnyFadeForTransition +{ + BOOL bottomBarIsVisible = [self.bottomDockingViewForPopup_internalOrDeveloper isKindOfClass:_LNPopupBottomBarSupport.class] == NO && self.ln_popupController.bottomBar.hidden == NO && self.ln_popupController.bottomBar.window != nil; + + return self.popupBar.window.safeAreaInsets.bottom != 0 || bottomBarIsVisible; +} + +- (BOOL)_ln_shouldPopupContentViewFadeForTransition +{ + BOOL bottomBarExtensionIsVisible = self._ln_bottomBarExtension_nocreate != nil && self._ln_bottomBarExtension_nocreate.isHidden == NO && self._ln_bottomBarExtension_nocreate.alpha > 0 && self._ln_bottomBarExtension_nocreate.frame.size.height > 0; + + BOOL bottomBarIsVisible = [self.bottomDockingViewForPopup_internalOrDeveloper isKindOfClass:_LNPopupBottomBarSupport.class] == NO && self.ln_popupController.bottomBar.hidden == NO && self.ln_popupController.bottomBar.window != nil; + + return bottomBarExtensionIsVisible == NO && bottomBarIsVisible == NO; +} + +- (void)_ln_popup_setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)overrideUserInterfaceStyle { [self _ln_popup_setOverrideUserInterfaceStyle:overrideUserInterfaceStyle]; - if(self._isContainedInPopupController) + if(@available(iOS 13.0, *)) { - [self.popupPresentationContainerViewController.popupContentView setControllerOverrideUserInterfaceStyle:overrideUserInterfaceStyle]; + if(self._isContainedInPopupController) + { + [self.popupPresentationContainerViewController.popupContentView setControllerOverrideUserInterfaceStyle:overrideUserInterfaceStyle]; + } } } @@ -323,7 +361,7 @@ static inline __attribute__((always_inline)) void _LNSetPopupSafeAreaInsets(id s { objc_setAssociatedObject(self, LNPopupAdditionalSafeAreaInsets, [NSValue valueWithUIEdgeInsets:additionalSafeAreaInsets], OBJC_ASSOCIATION_RETAIN_NONATOMIC); - UIEdgeInsets user = _LNUserSafeAreas(self); + UIEdgeInsets user = _LNUserSafeAreaInsets(self); _LNUpdateUserSafeAreaInsets(self, user, additionalSafeAreaInsets); } @@ -332,7 +370,7 @@ static inline __attribute__((always_inline)) void _LNSetPopupSafeAreaInsets(id s { objc_setAssociatedObject(self, LNUserAdditionalSafeAreaInsets, [NSValue valueWithUIEdgeInsets:additionalSafeAreaInsets], OBJC_ASSOCIATION_RETAIN_NONATOMIC); - UIEdgeInsets popup = _LNPopupSafeAreas(self); + UIEdgeInsets popup = _LNPopupSafeAreaInsets(self); _LNUpdateUserSafeAreaInsets(self, additionalSafeAreaInsets, popup); } @@ -342,12 +380,12 @@ static inline __attribute__((always_inline)) void _LNSetPopupSafeAreaInsets(id s objc_setAssociatedObject(self, LNPopupChildAdditiveSafeAreaInsets, [NSValue valueWithUIEdgeInsets:childAdditiveSafeAreaInsets], OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -UIEdgeInsets _LNPopupSafeAreas(id self) +UIEdgeInsets _LNPopupSafeAreaInsets(id self) { return [objc_getAssociatedObject(self, LNPopupAdditionalSafeAreaInsets) UIEdgeInsetsValue]; } -static inline __attribute__((always_inline)) UIEdgeInsets _LNUserSafeAreas(id self) +static inline __attribute__((always_inline)) UIEdgeInsets _LNUserSafeAreaInsets(id self) { return [objc_getAssociatedObject(self, LNUserAdditionalSafeAreaInsets) UIEdgeInsetsValue]; } @@ -359,8 +397,8 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) - (UIEdgeInsets)_ln_additionalSafeAreaInsets { - UIEdgeInsets user = _LNPopupSafeAreas(self); - UIEdgeInsets popup = _LNUserSafeAreas(self); + UIEdgeInsets user = _LNPopupSafeAreaInsets(self); + UIEdgeInsets popup = _LNUserSafeAreaInsets(self); return __LNEdgeInsetsSum(user, popup); } @@ -409,6 +447,18 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) } } +- (void)_ln_setNeedsUpdateOfHomeIndicatorAutoHidden +{ + if(self.popupPresentationContainerViewController) + { + [self.popupPresentationContainerViewController setNeedsUpdateOfHomeIndicatorAutoHidden]; + } + else + { + [self _ln_setNeedsUpdateOfHomeIndicatorAutoHidden]; + } +} + - (void)_ln_viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { if(self._ln_popupController_nocreate) @@ -437,21 +487,17 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) } [self _ln_willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; -} - -- (UIViewController*)_findAncestorParentPopupContainerController -{ - if(self._ln_popupController_nocreate) - { - return self; - } - if(self.parentViewController == nil) + if(@available(iOS 18.0, *)) { - return nil; + if([self isKindOfClass:UITabBarController.class]) + { + [coordinator animateAlongsideTransition:nil completion:^(id _Nonnull context) { + static SEL sel = NSSelectorFromString(LNPopupHiddenString("_forceUpdateScrollViewIfNecessary")); + [self performSelector:sel]; + }]; + } } - - return [self.parentViewController _findAncestorParentPopupContainerController]; } - (UIViewController*)_findChildInPopupPresentation @@ -512,6 +558,12 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) return vc ?: [self _ln_childViewControllerForStatusBarStyle]; } +- (nullable UIViewController *)_ln_common_childViewControllerForHomeIndicatorAutoHidden +{ + UIViewController* vc = [self _common_childViewControllersForStatusBarLogic]; + + return vc ?: [self _ln_childViewControllerForHomeIndicatorAutoHidden]; +} - (nullable UIViewController *)_ln_childViewControllerForStatusBarHidden { @@ -523,6 +575,11 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) return [self _ln_common_childViewControllerForStatusBarStyle]; } +- (nullable UIViewController *)_ln_childViewControllerForHomeIndicatorAutoHidden +{ + return [self _ln_common_childViewControllerForHomeIndicatorAutoHidden]; +} + - (void)_ln_setPopupPresentationState:(LNPopupPresentationState)newState { [self willChangeValueForKey:@"popupPresentationState"]; @@ -560,24 +617,13 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) //_updateContentOverlayInsetsFromParentIfNecessary (iOS 15 and above) - (void)_uCOIFPIN { - static SEL contentMarginSEL; - static SEL setContentMarginSEL; - static SEL _setContentOverlayInsets_andLeftMargin_rightMarginSEL; + static SEL contentMarginSEL = NSSelectorFromString(LNPopupHiddenString("_contentMargin")); + static SEL setContentMarginSEL = NSSelectorFromString(LNPopupHiddenString("_setContentMargin:")); + static SEL _setContentOverlayInsets_andLeftMargin_rightMarginSEL = NSSelectorFromString(LNPopupHiddenString("_setContentOverlayInsets:andLeftMargin:rightMargin:")); - static CGFloat (*contentMarginFunc)(id, SEL); - static void (*setContentMarginFunc)(id, SEL, CGFloat); - static void (*_setContentOverlayInsets_andLeftMargin_rightMarginFunc)(id, SEL, UIEdgeInsets, CGFloat, CGFloat); - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - contentMarginSEL = NSSelectorFromString(_LNPopupDecodeBase64String(cM)); - setContentMarginSEL = NSSelectorFromString(_LNPopupDecodeBase64String(sCM)); - _setContentOverlayInsets_andLeftMargin_rightMarginSEL = NSSelectorFromString(_LNPopupDecodeBase64String(sCOIaLMrM)); - - contentMarginFunc = (void*)objc_msgSend; - setContentMarginFunc = (void*)objc_msgSend; - _setContentOverlayInsets_andLeftMargin_rightMarginFunc = (void*)objc_msgSend; - }); + static CGFloat (*contentMarginFunc)(id, SEL) = reinterpret_cast(objc_msgSend); + static void (*setContentMarginFunc)(id, SEL, CGFloat) = reinterpret_cast(objc_msgSend); + static void (*_setContentOverlayInsets_andLeftMargin_rightMarginFunc)(id, SEL, UIEdgeInsets, CGFloat, CGFloat) = reinterpret_cast(objc_msgSend); if([self respondsToSelector:@selector(_ln_popupUIRequiresZeroInsets)] && self._ln_popupUIRequiresZeroInsets == YES) { @@ -589,11 +635,19 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) [self _uCOIFPIN]; + if(@available(iOS 17.0, *)) + { + if(__ln_alreadyInHideShowBar && __ln_hideBarEdge == UIRectEdgeBottom) + { + [self.view layoutIfNeeded]; + } + } + if(self.popupPresentationContainerViewController != nil) { CGFloat contentMargin = contentMarginFunc(self.popupPresentationContainerViewController, contentMarginSEL); - UIEdgeInsets insets = __LNEdgeInsetsSum(self.popupPresentationContainerViewController.view.safeAreaInsets, UIEdgeInsetsMake(0, 0, - _LNPopupSafeAreas(self.popupPresentationContainerViewController).bottom, 0)); + UIEdgeInsets insets = __LNEdgeInsetsSum(self.popupPresentationContainerViewController.view.safeAreaInsets, UIEdgeInsetsMake(0, 0, - _LNPopupSafeAreaInsets(self.popupPresentationContainerViewController).bottom, 0)); _setContentOverlayInsets_andLeftMargin_rightMarginFunc(self, _setContentOverlayInsets_andLeftMargin_rightMarginSEL, insets, contentMargin, contentMargin); setContentMarginFunc(self, setContentMarginSEL, contentMargin); @@ -603,13 +657,22 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) self.view.layoutMargins = UIEdgeInsetsMake(0, contentMargin, 0, contentMargin); } -#if ! TARGET_OS_MACCATALYST - if(self.popupContentViewController) + if([self.parentViewController isKindOfClass:UIPageViewController.class] && self.parentViewController._isContainedInPopupController) + { + //Work around Apple bugs + + CGFloat contentMargin = contentMarginFunc(self.parentViewController, contentMarginSEL); + UIEdgeInsets insets = self.parentViewController.view.safeAreaInsets; + + _setContentOverlayInsets_andLeftMargin_rightMarginFunc(self, _setContentOverlayInsets_andLeftMargin_rightMarginSEL, insets, contentMargin, contentMargin); + setContentMarginFunc(self, setContentMarginSEL, contentMargin); + } + + if(LNPopupBar.isCatalystApp && self.popupContentViewController) { [self.popupContentViewController _uLFSBAIO]; [self._ln_popupController_nocreate.popupContentView _repositionPopupCloseButton]; } -#endif } @@ -618,7 +681,7 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) { if([self _isContainedInPopupController]) { - return __LNEdgeInsetsSum(self.popupPresentationContainerViewController.view.safeAreaInsets, UIEdgeInsetsMake(0, 0, - _LNPopupSafeAreas(self.popupPresentationContainerViewController).bottom, 0)); + return __LNEdgeInsetsSum(self.popupPresentationContainerViewController.view.safeAreaInsets, UIEdgeInsetsMake(0, 0, - _LNPopupSafeAreaInsets(self.popupPresentationContainerViewController).bottom, 0)); } UIEdgeInsets insets = [self _vSAIFS]; @@ -643,23 +706,27 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) - (void)_layoutPopupBarOrderForTransition { [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_popupController_nocreate.popupBar aboveSubview:self.bottomDockingViewForPopup_internalOrDeveloper]; - [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_bottomBarExtension_nocreate belowSubview:self._ln_popupController_nocreate.popupBar]; + [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_bottomBarExtension_nocreate belowSubview:self.bottomDockingViewForPopup_internalOrDeveloper]; [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_popupController_nocreate.popupContentView belowSubview:self._ln_popupController_nocreate.popupBar]; } - (void)_layoutPopupBarOrderForUse { - [self.bottomDockingViewForPopup_internalOrDeveloper.superview bringSubviewToFront:self.bottomDockingViewForPopup_internalOrDeveloper]; - if(self._ln_popupController_nocreate.popupBar.resolvedStyle == LNPopupBarStyleFloating) + UIView* bottomBar = self.bottomDockingViewForPopup_internalOrDeveloper; + LNPopupBar* popupBar = self._ln_popupController_nocreate.popupBar; + UIView* parentForPopupBar = bottomBar.superview != nil ? bottomBar.superview : popupBar.superview; + + [bottomBar.superview bringSubviewToFront:bottomBar]; + if(popupBar.resolvedStyle == LNPopupBarStyleFloating) { - [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_popupController_nocreate.popupBar aboveSubview:self.bottomDockingViewForPopup_internalOrDeveloper]; + [parentForPopupBar insertSubview:popupBar aboveSubview:bottomBar]; } else { - [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_popupController_nocreate.popupBar belowSubview:self.bottomDockingViewForPopup_internalOrDeveloper]; + [parentForPopupBar insertSubview:popupBar belowSubview:bottomBar]; } - [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_bottomBarExtension_nocreate belowSubview:self._ln_popupController_nocreate.popupBar]; - [self._ln_popupController_nocreate.popupBar.superview insertSubview:self._ln_popupController_nocreate.popupContentView belowSubview:self._ln_popupController_nocreate.popupBar]; + [parentForPopupBar insertSubview:self._ln_bottomBarExtension_nocreate belowSubview:popupBar]; + [parentForPopupBar insertSubview:self._ln_popupController_nocreate.popupContentView aboveSubview:popupBar]; } - (_LNPopupBarBackgroundView*)_ln_bottomBarExtension_nocreate @@ -682,7 +749,7 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) { UIBlurEffectStyle effectStyle; - if (@available(iOS 13.0, *)) { + if(@available(iOS 13.0, *)) { effectStyle = UIBlurEffectStyleSystemChromeMaterial; } else { effectStyle = UIBlurEffectStyleLight; @@ -745,7 +812,7 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) { if(self.bottomDockingViewForPopup_nocreateOrDeveloper == self._ln_bottomBarSupport_nocreate) { - self._ln_bottomBarSupport_nocreate.frame = self.defaultFrameForBottomDockingView_internalOrDeveloper; + self._ln_bottomBarSupport_nocreate.frame = [self _defaultFrameForBottomDockingViewForPopupBar:self._ln_popupController_nocreate.popupBar]; [self.view bringSubviewToFront:self._ln_bottomBarSupport_nocreate]; self._ln_bottomBarExtension.frame = self._ln_bottomBarSupport_nocreate.frame; @@ -769,6 +836,29 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) { [self _layoutPopupBarOrderForUse]; } + + if(self._ln_popupController_nocreate.popupControllerInternalState != LNPopupPresentationStateBarHidden) + { + CGFloat barHeightToUse; + if(self._ln_popupController_nocreate.popupControllerPublicState == LNPopupPresentationStateOpen) + { + barHeightToUse = _LNPopupBarHeightForPopupBar(self.popupBar); + } + else + { + barHeightToUse = self.popupBar.frame.size.height; + } + + UIEdgeInsets neededInsets = UIEdgeInsetsMake(0, 0, MAX(0, barHeightToUse - [self _ln_popupOffsetForPopupBarStyle:self.popupBar.resolvedStyle]), 0); + + UIEdgeInsets safe = _LNPopupSafeAreaInsets(self); + UIEdgeInsets childAdditive = _LNPopupChildAdditiveSafeAreas(self); + + if(neededInsets.bottom != MAX(safe.bottom, childAdditive.bottom)) + { + _LNPopupSupportSetPopupInsetsForViewController(self, YES, neededInsets); + } + } } UIView* extensionView = self._ln_bottomBarExtension_nocreate; @@ -806,19 +896,19 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) Class superclass = LNDynamicSubclassSuper(self, _LN_UIViewController_AppearanceControl.class); struct objc_super super = {.receiver = self, .super_class = superclass}; - void (*super_class)(struct objc_super*, SEL, BOOL) = (void*)objc_msgSendSuper; + void (*super_class)(struct objc_super*, SEL, BOOL) = reinterpret_cast(objc_msgSendSuper); super_class(&super, @selector(viewWillAppear:), animated); __ln_popup_suppressViewControllerLifecycle = NO; } -- (void)_userFacing_viewIsAppearing:(BOOL)animated +- (void)_userFacing_viewIsAppearing:(BOOL)animated API_AVAILABLE(ios(13.0)) { __ln_popup_suppressViewControllerLifecycle = YES; Class superclass = LNDynamicSubclassSuper(self, _LN_UIViewController_AppearanceControl.class); struct objc_super super = {.receiver = self, .super_class = superclass}; - void (*super_class)(struct objc_super*, SEL, BOOL) = (void*)objc_msgSendSuper; + void (*super_class)(struct objc_super*, SEL, BOOL) = reinterpret_cast(objc_msgSendSuper); super_class(&super, @selector(viewIsAppearing:), animated); __ln_popup_suppressViewControllerLifecycle = NO; @@ -830,7 +920,7 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) Class superclass = LNDynamicSubclassSuper(self, _LN_UIViewController_AppearanceControl.class); struct objc_super super = {.receiver = self, .super_class = superclass}; - void (*super_class)(struct objc_super*, SEL, BOOL) = (void*)objc_msgSendSuper; + void (*super_class)(struct objc_super*, SEL, BOOL) = reinterpret_cast(objc_msgSendSuper); super_class(&super, @selector(viewDidAppear:), animated); __ln_popup_suppressViewControllerLifecycle = NO; @@ -842,7 +932,7 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) Class superclass = LNDynamicSubclassSuper(self, _LN_UIViewController_AppearanceControl.class); struct objc_super super = {.receiver = self, .super_class = superclass}; - void (*super_class)(struct objc_super*, SEL, BOOL) = (void*)objc_msgSendSuper; + void (*super_class)(struct objc_super*, SEL, BOOL) = reinterpret_cast(objc_msgSendSuper); super_class(&super, @selector(viewWillDisappear:), animated); __ln_popup_suppressViewControllerLifecycle = NO; @@ -854,7 +944,7 @@ UIEdgeInsets _LNPopupChildAdditiveSafeAreas(id self) Class superclass = LNDynamicSubclassSuper(self, _LN_UIViewController_AppearanceControl.class); struct objc_super super = {.receiver = self, .super_class = superclass}; - void (*super_class)(struct objc_super*, SEL, BOOL) = (void*)objc_msgSendSuper; + void (*super_class)(struct objc_super*, SEL, BOOL) = reinterpret_cast(objc_msgSendSuper); super_class(&super, @selector(viewDidDisappear:), animated); __ln_popup_suppressViewControllerLifecycle = NO; @@ -900,21 +990,33 @@ static void __LNPopupUpdateChildInsets(UIViewController* controller) _LNSetPopupSafeAreaInsets(controller, popupSafeAreaInsets); } -void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller, BOOL layout, UIEdgeInsets popupEdgeInsets) +void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller, BOOL wantsLayout, UIEdgeInsets popupEdgeInsets) { + BOOL shouldLayout = NO; + //Container classes with bottom bars have bugs if additional safe areas are applied directly to them. //Instead, set a custom property and update their children recursively to take care of the additional safe area. if(__LNPopupIsClassBuggyForAdditionalSafeArea(controller) == YES) { - [controller _ln_setChildAdditiveSafeAreaInsets:popupEdgeInsets]; - __LNPopupUpdateChildInsets(controller); + UIEdgeInsets current = _LNPopupChildAdditiveSafeAreas(controller); + if(UIEdgeInsetsEqualToEdgeInsets(current, popupEdgeInsets) == NO) + { + shouldLayout = YES; + [controller _ln_setChildAdditiveSafeAreaInsets:popupEdgeInsets]; + __LNPopupUpdateChildInsets(controller); + } } else { - _LNSetPopupSafeAreaInsets(controller, popupEdgeInsets); + UIEdgeInsets current = _LNPopupSafeAreaInsets(controller); + if(UIEdgeInsetsEqualToEdgeInsets(current, popupEdgeInsets) == NO) + { + shouldLayout = YES; + _LNSetPopupSafeAreaInsets(controller, popupEdgeInsets); + } } - if(layout) + if(wantsLayout && shouldLayout) { [controller.view setNeedsUpdateConstraints]; [controller.view setNeedsLayout]; @@ -927,15 +1029,59 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller @interface UITabBarController (LNPopupSupportPrivate) @end @implementation UITabBarController (LNPopupSupportPrivate) +- (void)_layoutPopupBarOrderForUse +{ + if(@available(iOS 18.0, *)) + { + LNPopupBar* popupBar = self._ln_popupController_nocreate.popupBar; + popupBar._hackyMargins = NSDirectionalEdgeInsetsZero; + + static NSString* outlineViewKey = LNPopupHiddenString("_outlineView"); + UIView* outlineView = [self.sidebar valueForKey:outlineViewKey]; + + if(self.tabBar.superview != nil || outlineView == nil) + { + [super _layoutPopupBarOrderForUse]; + [popupBar layoutIfNeeded]; + return; + } + + static NSString* tabContainerViewKey = LNPopupHiddenString("visualStyle.tabContainerView"); + UIView* parentForPopupBar = [self valueForKeyPath:tabContainerViewKey]; + + static NSString* sidebarLayoutKey = LNPopupHiddenString("sidebarLayout"); + + NSUInteger sidebarLayout = [[parentForPopupBar valueForKey:sidebarLayoutKey] unsignedIntegerValue]; + + if(sidebarLayout == 0) + { + popupBar._hackyMargins = NSDirectionalEdgeInsetsMake(0, self.sidebar.isHidden ? 0 : outlineView.bounds.size.width, 0, 0); + [super _layoutPopupBarOrderForUse]; + [popupBar layoutIfNeeded]; + return; + } + + [parentForPopupBar insertSubview:popupBar atIndex:0]; + [parentForPopupBar insertSubview:self._ln_bottomBarExtension_nocreate belowSubview:popupBar]; + [parentForPopupBar insertSubview:self._ln_popupController_nocreate.popupContentView atIndex:parentForPopupBar.subviews.count]; + + [popupBar layoutIfNeeded]; + + return; + } + + [super _layoutPopupBarOrderForUse]; +} + - (BOOL)_isTabBarHiddenDuringTransition { NSNumber* isHidden = objc_getAssociatedObject(self, LNToolbarHiddenBeforeTransition); - return isHidden.boolValue; + return isHidden.boolValue || self.tabBar.superview == nil; } -- (void)_setTabBarHiddenDuringTransition:(BOOL)toolbarHidden +- (void)_setTabBarHiddenDuringTransition:(BOOL)tabBarHidden { - objc_setAssociatedObject(self, LNToolbarHiddenBeforeTransition, @(toolbarHidden), OBJC_ASSOCIATION_RETAIN); + objc_setAssociatedObject(self, LNToolbarHiddenBeforeTransition, @(tabBarHidden), OBJC_ASSOCIATION_RETAIN); } - (BOOL)_isPrepareTabBarIgnored @@ -964,6 +1110,11 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller return self.tabBar.hidden == NO && self._isTabBarHiddenDuringTransition == NO ? UIEdgeInsetsZero : self.view.superview.safeAreaInsets; } +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle +{ + return self._isTabBarHiddenDuringTransition ? [super _ln_popupOffsetForPopupBarStyle:barStyle] : 0; +} + - (CGRect)defaultFrameForBottomDockingView { CGRect bottomBarFrame = self.tabBar.frame; @@ -983,6 +1134,10 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller @selector(childViewControllerForStatusBarHidden), @selector(_ln_childViewControllerForStatusBarHidden)); + LNSwizzleMethod(self, + @selector(childViewControllerForHomeIndicatorAutoHidden), + @selector(_ln_childViewControllerForHomeIndicatorAutoHidden)); + LNSwizzleMethod(self, @selector(viewDidLayoutSubviews), @selector(_ln_popup_viewDidLayoutSubviews_tvc)); @@ -998,25 +1153,43 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller #ifndef LNPopupControllerEnforceStrictClean NSString* selName; - //_hideBarWithTransition:isExplicit:duration: - selName = _LNPopupDecodeBase64String(hBWTiEDBase64); - LNSwizzleMethod(self, - NSSelectorFromString(selName), - @selector(hBWT:iE:d:)); + selName = LNPopupHiddenString("_hideBarWithTransition:isExplicit:duration:reason:"); + if([self instancesRespondToSelector:NSSelectorFromString(selName)]) + { + LNSwizzleMethod(self, + NSSelectorFromString(selName), + @selector(hBWT:iE:d:r:)); + } + else + { + selName = LNPopupHiddenString("_hideBarWithTransition:isExplicit:duration:"); + LNSwizzleMethod(self, + NSSelectorFromString(selName), + @selector(hBWT:iE:d:)); + } - //_showBarWithTransition:isExplicit:duration: - selName = _LNPopupDecodeBase64String(sBWTiEDBase64); - LNSwizzleMethod(self, - NSSelectorFromString(selName), - @selector(sBWT:iE:d:)); + selName = LNPopupHiddenString("_showBarWithTransition:isExplicit:duration:reason:"); + if([self instancesRespondToSelector:NSSelectorFromString(selName)]) + { + //_showBarWithTransition:isExplicit:duration:reason: + LNSwizzleMethod(self, + NSSelectorFromString(selName), + @selector(sBWT:iE:d:r:)); + } + else + { + selName = LNPopupHiddenString("_showBarWithTransition:isExplicit:duration:"); + LNSwizzleMethod(self, + NSSelectorFromString(selName), + @selector(sBWT:iE:d:)); + } - //_updateLayoutForStatusBarAndInterfaceOrientation - selName = _LNPopupDecodeBase64String(uLFSBAIO); + selName = LNPopupHiddenString("_updateLayoutForStatusBarAndInterfaceOrientation"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_uLFSBAIO)); - selName = _LNPopupDecodeBase64String(pTBBase64); + selName = LNPopupHiddenString("_prepareTabBar"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_ln_pTB)); @@ -1028,7 +1201,7 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller { if(self._ln_popupController_nocreate.popupControllerInternalState != LNPopupPresentationStateBarHidden) { - if(self.tabBar.isHidden == NO && self._isTabBarHiddenDuringTransition == NO && self._ignoringLayoutDuringTransition == NO) + if(self.tabBar.isHidden == NO && self._isTabBarHiddenDuringTransition == NO && self._ignoringLayoutDuringTransition == NO && self._ln_isFloatingTabBar == NO) { self._ln_bottomBarExtension_nocreate.hidden = YES; [self._ln_bottomBarExtension_nocreate removeFromSuperview]; @@ -1037,11 +1210,17 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller { self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 1.0; } + } else { self._ln_bottomBarExtension.hidden = NO; + if(self._ln_isFloatingTabBar == YES) + { + self._ln_bottomBarExtension_nocreate.alpha = 1.0; + } + if(self._ln_popupController_nocreate.popupBar.resolvedStyle == LNPopupBarStyleFloating && self._ignoringLayoutDuringTransition == NO) { self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 0.0; @@ -1059,7 +1238,9 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller if(self._ignoringLayoutDuringTransition == NO) { CGFloat bottomSafeArea = self.view.superview.safeAreaInsets.bottom; - self._ln_bottomBarExtension_nocreate.frame = CGRectMake(0, self.view.bounds.size.height - bottomSafeArea, self.view.bounds.size.width, bottomSafeArea); + CGRect frame = CGRectMake(0, self.view.bounds.size.height - bottomSafeArea, self.view.bounds.size.width, bottomSafeArea); + UIEdgeInsets hackyInsets = _LNEdgeInsetsFromDirectionalEdgeInsets(self._ln_popupController_nocreate.popupBar, self._ln_popupController_nocreate.popupBar._hackyMargins); + self._ln_bottomBarExtension_nocreate.frame = UIEdgeInsetsInsetRect(frame, hackyInsets); } } @@ -1107,9 +1288,122 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller self._ln_popupController_nocreate.popupBar.frame = frame; } +- (void)_ln_animateAlongsideTransition:(NSUInteger)transition withDuration:(NSTimeInterval)duration animations:(void (^ __nullable)(id context))animations completion:(void (^ __nullable)(id context))completion +{ + id transitionCoordinator = self.selectedViewController.transitionCoordinator; + + __weak __typeof(self) weakSelf = self; + + if(transitionCoordinator != nil) + { + [transitionCoordinator animateAlongsideTransition:animations completion:^(id _Nonnull context) { + if(completion != nil) + { + completion(context); + } + }]; + } + else + { + __LNFakeContext* ctx = [__LNFakeContext new]; + ctx.cancelled = NO; + if(duration != 0) + { + if(duration == -1) + { + duration = __ln_durationForTransition(self, transition); + } + + [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionLayoutSubviews animations:^{ + if(animations != nil) + { + animations((id)ctx); + } + } completion:^(BOOL finished) { + if(completion != nil) + { + completion((id)ctx); + } + }]; + } + else + { + [UIView performWithoutAnimation:^{ + if(animations != nil) + { + animations((id)ctx); + } + if(completion != nil) + { + completion((id)ctx); + } + }]; + } + } +} + +- (BOOL)_ln_isFloatingTabBar +{ + if(unavailable(iOS 18.0, *)) + { + return NO; + } + + if(self.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPad && self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) + { + return YES; + } + + return NO; +} + //_hideBarWithTransition:isExplicit:duration: - (void)hBWT:(NSInteger)t iE:(BOOL)e d:(NSTimeInterval)duration { + [self hBWT:t iE:e d:duration r:NSUIntegerMax]; +} + +//_hideBarWithTransition:isExplicit:duration:reason: +- (void)hBWT:(NSInteger)transition iE:(BOOL)isExplicit d:(NSTimeInterval)duration r:(NSUInteger)reason +{ + if(self._ln_popupController_nocreate.popupControllerInternalState == LNPopupPresentationStateBarHidden || self._ln_isFloatingTabBar == YES) + { + [self _setTabBarHiddenDuringTransition:YES]; + + if(@available(iOS 18.0, *)) + { + [self hBWT:transition iE:isExplicit d:duration r:reason]; + } + else + { + [self hBWT:transition iE:isExplicit d:duration]; + } + + [self _ln_animateAlongsideTransition:transition withDuration:duration animations:^(id context) { + if(transition != 1) + { + [self _ln_updateSafeAreaInsets]; + [self.view layoutIfNeeded]; + } + } completion:nil]; + + return; + } + + if(__ln_alreadyInHideShowBar == YES) + { + //Ignore nested calls to _hideBarWithTransition:isExplicit:duration:reason: + if(@available(iOS 18.0, *)) + { + [self hBWT:transition iE:isExplicit d:duration r:reason]; + } + else + { + [self hBWT:transition iE:isExplicit d:duration]; + } + return; + } + BOOL isFloating = self._ln_popupController_nocreate.popupBar.resolvedStyle == LNPopupBarStyleFloating; if(!isFloating) { @@ -1123,25 +1417,64 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller [self _setTabBarHiddenDuringTransition:YES]; CGRect frame = self.tabBar.frame; - if(t != 0) + if(transition == 1) { frame.origin.x = (isRTL ? -1 : 1) * self.view.bounds.size.width; } self._ln_bottomBarExtension.frame = frame; self._ln_bottomBarExtension_nocreate.hidden = NO; self._ln_bottomBarExtension_nocreate.alpha = 1.0; - [self hBWT:t iE:e d:duration]; + + [self._ln_bottomBarExtension layoutIfNeeded]; + + __ln_alreadyInHideShowBar = YES; + if(@available(iOS 18.0, *)) + { + [self hBWT:transition iE:isExplicit d:duration r:reason]; + } + else + { + [self hBWT:transition iE:isExplicit d:duration]; + } + __ln_alreadyInHideShowBar = NO; + + if(transition != 1 && isExplicit == NO) + { + return; + } NSString* effectGroupingIdentifier = self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier; - self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = nil; + NSString* traitOverride = nil; + + if(@available(iOS 17.0, *)) + { + traitOverride = [self._ln_popupController_nocreate.bottomBar.traitCollection objectForTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } + + if(transition == 1) + { + if(@available(iOS 17.0, *)) + { + [self._ln_popupController_nocreate.bottomBar.traitOverrides setObject:nil forTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } + else + { + self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = nil; + } + } + else + { + self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 0.0; + } self._ln_popupController_nocreate.popupBar.wantsBackgroundCutout = NO; - if(t == 1 && isFloating) + if(transition == 1 && isFloating) { self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.alpha = 0.0; self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.hidden = NO; } + [self.tabBar _setIgnoringLayoutDuringTransition:YES]; [self _setIgnoringLayoutDuringTransition:YES]; CGFloat bottomSafeArea = self.view.superview.safeAreaInsets.bottom; @@ -1153,26 +1486,45 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller self._ln_bottomBarExtension_nocreate.alpha = 1.0; void (^animations)(id) = ^ (id _Nonnull context) { + if(transition != 1) + { + [self _ln_updateSafeAreaInsets]; + [self.view layoutIfNeeded]; + } + self._ln_bottomBarExtension_nocreate.frame = CGRectMake(0, self.view.bounds.size.height - bottomSafeArea, self.view.bounds.size.width, self._ln_bottomBarExtension_nocreate.frame.size.height); - self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 0.0; + + if(transition == 1) + { + self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 0.0; + } [self __repositionPopupBarToClosed_hack]; + if(isFloating) { [self._ln_popupController_nocreate.popupBar layoutIfNeeded]; - self._ln_popupController_nocreate.popupBar.backgroundView.frame = CGRectOffset(backgroundViewFrame, (isRTL ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(frame) + bottomSafeArea); self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 1.0; - if(t == 1) + + if(transition == 1) { + self._ln_popupController_nocreate.popupBar.backgroundView.frame = CGRectOffset(backgroundViewFrame, (isRTL ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(frame) + bottomSafeArea); self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.alpha = 1.0; } + else + { + self._ln_popupController_nocreate.popupBar.backgroundView.frame = CGRectOffset(backgroundViewFrame, 0, bottomSafeArea); + self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 0.0; + } } }; void (^completion)(id) = ^ (id _Nonnull context) { + [self.tabBar _setIgnoringLayoutDuringTransition:NO]; + if(isFloating) { - if(t == 1) + if(transition == 1) { self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.alpha = 0.0; self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.hidden = YES; @@ -1184,57 +1536,72 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller self._ln_bottomBarExtension_nocreate.frame = CGRectMake(0, self.view.bounds.size.height - bottomSafeArea, self.view.bounds.size.width, bottomSafeArea); [self _setIgnoringLayoutDuringTransition:NO]; + [self._ln_popupController_nocreate _popupBarMetricsDidChange:self._ln_popupController_nocreate.popupBar shouldLayout:NO]; [self._ln_popupController_nocreate _setContentToState:self._ln_popupController_nocreate.popupControllerInternalState]; self._ln_popupController_nocreate.popupBar.bottomShadowView.hidden = YES; self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 1.0; - self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = effectGroupingIdentifier; + if(@available(iOS 17.0, *)) + { + [self._ln_popupController_nocreate.bottomBar.traitOverrides setObject:traitOverride forTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } + else + { + self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = effectGroupingIdentifier; + } self._ln_popupController_nocreate.popupBar.backgroundView.frame = backgroundViewFrame; [self _layoutPopupBarOrderForUse]; }; - id transitionCoordinator = self.selectedViewController.transitionCoordinator; - - if(transitionCoordinator != nil) - { - [transitionCoordinator animateAlongsideTransition:animations completion:completion]; - } - else - { - [UIView performWithoutAnimation:^{ - animations(nil); - completion(nil); - }]; - } + [self _ln_animateAlongsideTransition:transition withDuration:duration animations:animations completion:completion]; } //_showBarWithTransition:isExplicit:duration: - (void)sBWT:(NSInteger)t iE:(BOOL)e d:(NSTimeInterval)duration { + [self sBWT:t iE:e d:duration r:NSUIntegerMax]; +} + +//_showBarWithTransition:isExplicit:duration:reason: +- (void)sBWT:(NSInteger)transition iE:(BOOL)isExplicit d:(NSTimeInterval)duration r:(NSUInteger)reason +{ + if(__ln_alreadyInHideShowBar == YES) + { + //Ignore nested calls to _showBarWithTransition:isExplicit:duration: + if(@available(iOS 18.0, *)) + { + [self sBWT:transition iE:isExplicit d:duration r:reason]; + } + else + { + [self sBWT:transition iE:isExplicit d:duration]; + } + return; + } + BOOL isFloating = self._ln_popupController_nocreate.popupBar.resolvedStyle == LNPopupBarStyleFloating; BOOL isRTL = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.tabBar.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft; - if(e == YES) - { - if(!isFloating) - { - self._ln_popupController_nocreate.popupBar.bottomShadowView.hidden = NO; - } - - [self _setPrepareTabBarIgnored:YES]; - } - [self._ln_popupController_nocreate.popupBar _cancelGestureRecognizers]; - BOOL wasHidden = self.tabBar.isHidden; + BOOL wasHidden = self.tabBar.isHidden || self._isTabBarHiddenDuringTransition; - [self sBWT:t iE:e d:duration]; + __ln_alreadyInHideShowBar = YES; + if(@available(iOS 18.0, *)) + { + [self sBWT:transition iE:isExplicit d:duration r:reason]; + } + else + { + [self sBWT:transition iE:isExplicit d:duration]; + } + __ln_alreadyInHideShowBar = NO; - if(e == NO) + if(isExplicit == NO) { return; } @@ -1244,45 +1611,92 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller return; } - self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 0.0; - self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 1.0; - - if(wasHidden == YES) + if(self._ln_isFloatingTabBar == YES) { - self._ln_popupController_nocreate.popupBar.wantsBackgroundCutout = NO; + [self.view setNeedsLayout]; + [self _setTabBarHiddenDuringTransition:NO]; + + return; } - if(t == 2 && isFloating) + if(!isFloating) { + self._ln_popupController_nocreate.popupBar.bottomShadowView.hidden = NO; + } + + [self _setPrepareTabBarIgnored:YES]; + + self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 0.0; + + self._ln_popupController_nocreate.popupBar.wantsBackgroundCutout = NO; + + __block CGRect frame = self.tabBar.frame; + + __block CGRect backgroundViewFrame = self._ln_popupController_nocreate.popupBar.backgroundView.frame; + CGFloat bottomSafeArea = self.view.superview.safeAreaInsets.bottom; + if(transition == 2 && isFloating) + { + self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 1.0; self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.alpha = 1.0; self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.hidden = NO; + + CGRect initial = CGRectOffset(backgroundViewFrame, (isRTL ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(frame) + bottomSafeArea); + + self._ln_popupController_nocreate.popupBar.backgroundView.frame = initial; } - - CGRect backgroundViewFrame = self._ln_popupController_nocreate.popupBar.backgroundView.frame; - if(isFloating && wasHidden == YES) + else if(isFloating) { - self._ln_popupController_nocreate.popupBar.backgroundView.frame = CGRectOffset(backgroundViewFrame, (isRTL ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(self.tabBar.frame) + self.view.superview.safeAreaInsets.bottom); + self._ln_popupController_nocreate.popupBar.backgroundView.frame = CGRectOffset(backgroundViewFrame, 0, bottomSafeArea); } - __block CGRect frame = self.tabBar.frame; [self _setIgnoringLayoutDuringTransition:YES]; NSString* effectGroupingIdentifier = self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier; - self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = nil; + NSString* traitOverride = nil; + + if(@available(iOS 17.0, *)) + { + traitOverride = [self._ln_popupController_nocreate.bottomBar.traitCollection objectForTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } + + if(transition == 2) + { + if(@available(iOS 17.0, *)) + { + [self._ln_popupController_nocreate.bottomBar.traitOverrides setObject:nil forTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } + else + { + self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = nil; + } + } void (^animations)(id) = ^ (id _Nonnull context) { + if(transition != 2) + { + [self _ln_updateSafeAreaInsets]; + [self.view layoutIfNeeded]; + } + [UIView performWithoutAnimation:^{ self.tabBar.frame = frame; }]; - frame.origin.x += (isRTL ? -1 : 1) * self.view.bounds.size.width; + if(transition == 2) + { + frame.origin.x += (isRTL ? -1 : 1) * self.view.bounds.size.width; + } self._ln_bottomBarExtension.frame = frame; - self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 1.0; - if(isFloating && wasHidden == YES) + + if(transition == 2) + { + self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 1.0; + } + if(isFloating) { self._ln_popupController_nocreate.popupBar.backgroundView.frame = backgroundViewFrame; self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 1.0; - if(t == 2) + if(transition == 2) { self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.alpha = 0.0; } @@ -1296,12 +1710,9 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller void (^completion)(id) = ^ (id _Nonnull context) { [self _setPrepareTabBarIgnored:NO]; - if(wasHidden == YES) - { - [self._ln_popupController_nocreate.popupBar setWantsBackgroundCutout:YES allowImplicitAnimations:YES]; - } + [self._ln_popupController_nocreate.popupBar setWantsBackgroundCutout:YES allowImplicitAnimations:YES]; - if(t == 2 && isFloating) + if(transition == 2 && isFloating) { self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.alpha = 0.0; self._ln_popupController_nocreate.popupBar.backgroundView.transitionShadingView.hidden = YES; @@ -1320,13 +1731,21 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller self._ln_popupController_nocreate.popupBar.bottomShadowView.hidden = YES; self._ln_popupController_nocreate.popupBar.bottomShadowView.alpha = 1.0; + [self._ln_popupController_nocreate _popupBarMetricsDidChange:self._ln_popupController_nocreate.popupBar shouldLayout:NO]; [self._ln_popupController_nocreate _setContentToState:self._ln_popupController_nocreate.popupControllerInternalState]; [self _layoutPopupBarOrderForUse]; [self _setIgnoringLayoutDuringTransition:NO]; - self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = effectGroupingIdentifier; + if(@available(iOS 17.0, *)) + { + [self._ln_popupController_nocreate.bottomBar.traitOverrides setObject:traitOverride forTrait:_LNPopupBarBackgroundGroupNameOverride.class]; + } + else + { + self._ln_popupController_nocreate.popupBar.effectGroupingIdentifier = effectGroupingIdentifier; + } if(context.isCancelled == NO) { @@ -1334,21 +1753,7 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller } }; - id transitionCoordinator = self.selectedViewController.transitionCoordinator; - - if(transitionCoordinator != nil) - { - [transitionCoordinator animateAlongsideTransition:animations completion:completion]; - } - else - { - [UIView performWithoutAnimation:^{ - __LNFakeContext* ctx = [__LNFakeContext new]; - ctx.cancelled = NO; - animations((id)ctx); - completion((id)ctx); - }]; - } + [self _ln_animateAlongsideTransition:transition withDuration:duration animations:animations completion:completion]; } //_prepareTabBar @@ -1366,6 +1771,16 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller self.tabBar.frame = oldBarFrame; } } + +//updateTabBarLayout +- (void)_ln_uTBL +{ + if(self._ignoringLayoutDuringTransition == NO) + { + [self _ln_uTBL]; + } +} + #endif - (nullable UIViewController *)_ln_childViewControllerForStatusBarHidden @@ -1378,6 +1793,11 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller return [self _ln_common_childViewControllerForStatusBarStyle]; } +- (nullable UIViewController *)_ln_childViewControllerForHomeIndicatorAutoHidden +{ + return [self _ln_common_childViewControllerForHomeIndicatorAutoHidden]; +} + @end #pragma mark - UINavigationController @@ -1395,16 +1815,24 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller return self.toolbar; } +- (CGFloat)_ln_popupOffsetForPopupBarStyle:(LNPopupBarStyle)barStyle +{ + return self.isToolbarHidden ? [super _ln_popupOffsetForPopupBarStyle:barStyle] : 0; +} + - (CGRect)defaultFrameForBottomDockingView { CGRect toolbarBarFrame = self.toolbar.frame; - CGFloat bottomSafeAreaHeight = self.view.safeAreaInsets.bottom; - if([NSStringFromClass(self.nonMemoryLeakingPresentationController.class) containsString:@"Preview"] == NO) + CGFloat bottomSafeAreaHeight = 0.0; + if(unavailable(iOS 18.0, *)) { - bottomSafeAreaHeight -= self.view.window.safeAreaInsets.bottom; + bottomSafeAreaHeight = self.view.safeAreaInsets.bottom; + if([NSStringFromClass(self.nonMemoryLeakingPresentationController.class) containsString:@"Preview"] == NO) + { + bottomSafeAreaHeight -= self.view.window.safeAreaInsets.bottom; + } } - toolbarBarFrame.origin = CGPointMake(toolbarBarFrame.origin.x, self.view.bounds.size.height - (self.isToolbarHidden ? 0.0 : toolbarBarFrame.size.height) - bottomSafeAreaHeight); return toolbarBarFrame; @@ -1412,12 +1840,31 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller - (UIEdgeInsets)insetsForBottomDockingView { - if(self.presentingViewController != nil && [NSStringFromClass(self.nonMemoryLeakingPresentationController.class) containsString:@"Preview"]) + if(@available(iOS 18.0, *)) { - return UIEdgeInsetsZero; + CGFloat offset = 0; + + if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + static auto key = LNPopupHiddenString("_backgroundView.bounds"); + if([[self.toolbar valueForKeyPath:key] CGRectValue].size.height < (self.toolbar.bounds.size.height + self.view.safeAreaInsets.bottom)) + { + //Something in UIKit reports safe area insets incorrectly on iPadOS. This is a workaround for this issue. + offset -= 5; + } + } + + return UIEdgeInsetsMake(0, 0, self.view.safeAreaInsets.bottom + offset, 0); + } + else + { + if(self.presentingViewController != nil && [NSStringFromClass(self.nonMemoryLeakingPresentationController.class) containsString:@"Preview"]) + { + return UIEdgeInsetsZero; + } + + return UIEdgeInsetsMake(0, 0, MAX(self.view.superview.safeAreaInsets.bottom, self.view.window.safeAreaInsets.bottom), 0); } - - return UIEdgeInsetsMake(0, 0, MAX(self.view.superview.safeAreaInsets.bottom, self.view.window.safeAreaInsets.bottom), 0); } + (void)load @@ -1432,6 +1879,10 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller @selector(childViewControllerForStatusBarHidden), @selector(_ln_childViewControllerForStatusBarHidden)); + LNSwizzleMethod(self, + @selector(childViewControllerForHomeIndicatorAutoHidden), + @selector(_ln_childViewControllerForHomeIndicatorAutoHidden)); + LNSwizzleMethod(self, @selector(setNavigationBarHidden:animated:), @selector(_ln_setNavigationBarHidden:animated:)); @@ -1463,20 +1914,17 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller #ifndef LNPopupControllerEnforceStrictClean NSString* selName; - //_setToolbarHidden:edge:duration: - selName = _LNPopupDecodeBase64String(sTHedBase64); + selName = LNPopupHiddenString("_setToolbarHidden:edge:duration:"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_sTH:e:d:)); - //_hideShowNavigationBarDidStop:finished:context: - selName = _LNPopupDecodeBase64String(hSNBDSfcBase64); + selName = LNPopupHiddenString("_hideShowNavigationBarDidStop:finished:context:"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(hSNBDS:f:c:)); - //_updateLayoutForStatusBarAndInterfaceOrientation - selName = _LNPopupDecodeBase64String(uLFSBAIO); + selName = LNPopupHiddenString("_updateLayoutForStatusBarAndInterfaceOrientation"); LNSwizzleMethod(self, NSSelectorFromString(selName), @selector(_uLFSBAIO)); @@ -1609,8 +2057,19 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller BOOL wasToolbarHidden = self.isToolbarHidden; + if(edge == UIRectEdgeBottom && wasToolbarHidden != hidden) + { + [self _setIgnoringLayoutDuringTransition:YES]; + } + + CGFloat earlyBarOffset = [self _ln_popupOffsetForPopupBarStyle:self._ln_popupController_nocreate.popupBar.resolvedStyle]; + + __ln_hideBarEdge = edge; + __ln_alreadyInHideShowBar = YES; //Trigger the toolbar hide or show transition. [self _sTH:hidden e:edge d:duration]; + __ln_alreadyInHideShowBar = NO; + __ln_hideBarEdge = UIRectEdgeNone; if(wasToolbarHidden != hidden) { @@ -1628,37 +2087,40 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller self._ln_bottomBarExtension_nocreate.alpha = 1.0; } + CGFloat bottomSafeArea = self.view.superview.safeAreaInsets.bottom; CGRect backgroundViewFrame = self._ln_popupController_nocreate.popupBar.backgroundView.frame; CGRect initialBackgroundViewFrame; CGRect targetBackgroundViewFrame; + CGFloat laterBarOffset = [self _ln_popupOffsetForPopupBarStyle:self._ln_popupController_nocreate.popupBar.resolvedStyle]; + if(edge == UIRectEdgeBottom) { if(hidden == YES) { initialBackgroundViewFrame = backgroundViewFrame; - targetBackgroundViewFrame = CGRectOffset(backgroundViewFrame, 0, CGRectGetHeight(frame)); + targetBackgroundViewFrame = CGRectOffset(backgroundViewFrame, 0, bottomSafeArea - laterBarOffset); } else { - initialBackgroundViewFrame = CGRectOffset(backgroundViewFrame, 0, CGRectGetHeight(frame)); + initialBackgroundViewFrame = CGRectOffset(backgroundViewFrame, 0, bottomSafeArea - earlyBarOffset); targetBackgroundViewFrame = backgroundViewFrame; } } else if(hidden == YES) { initialBackgroundViewFrame = backgroundViewFrame; - targetBackgroundViewFrame = CGRectOffset(backgroundViewFrame, (edge == UIRectEdgeRight ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(frame) + self.view.superview.safeAreaInsets.bottom); + targetBackgroundViewFrame = CGRectOffset(backgroundViewFrame, (edge == UIRectEdgeRight ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(frame) + bottomSafeArea - laterBarOffset); } else { - initialBackgroundViewFrame = CGRectOffset(backgroundViewFrame, (edge == UIRectEdgeRight ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(frame) + self.view.superview.safeAreaInsets.bottom); + initialBackgroundViewFrame = CGRectOffset(backgroundViewFrame, (edge == UIRectEdgeRight ? 1 : -1) * CGRectGetWidth(backgroundViewFrame), -CGRectGetHeight(frame) + bottomSafeArea - earlyBarOffset); targetBackgroundViewFrame = backgroundViewFrame; } if(isFloating) { - self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 1.0; + self._ln_popupController_nocreate.popupBar.backgroundView.alpha = (hidden == YES || edge != UIRectEdgeBottom) ? 1.0 : 0.0; self._ln_popupController_nocreate.popupBar.backgroundView.frame = initialBackgroundViewFrame; } @@ -1669,6 +2131,7 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller [self _layoutPopupBarOrderForTransition]; void (^animations)(void) = ^ { + [self._ln_popupController_nocreate _popupBarMetricsDidChange:self._ln_popupController_nocreate.popupBar shouldLayout:NO]; //During the transition, animate the popup bar and content together with the toolbar transition. [self._ln_popupController_nocreate _setContentToState:self._ln_popupController_nocreate.popupControllerInternalState]; @@ -1686,7 +2149,7 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller if(isFloating) { - self._ln_popupController_nocreate.popupBar.backgroundView.alpha = 1.0; + self._ln_popupController_nocreate.popupBar.backgroundView.alpha = edge == UIRectEdgeBottom ? 0.0 : 1.0; } } else @@ -1734,12 +2197,13 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller self._ln_popupController_nocreate.popupBar.backgroundView.frame = backgroundViewFrame; - [self _layoutPopupBarOrderForUse]; - [self _setIgnoringLayoutDuringTransition:NO]; }; - [self _setIgnoringLayoutDuringTransition:YES]; + if(edge != UIRectEdgeBottom) + { + [self _setIgnoringLayoutDuringTransition:YES]; + } if(duration == 0) { @@ -1787,6 +2251,11 @@ void _LNPopupSupportSetPopupInsetsForViewController(UIViewController* controller return [self _ln_common_childViewControllerForStatusBarStyle]; } +- (nullable UIViewController *)_ln_childViewControllerForHomeIndicatorAutoHidden +{ + return [self _ln_common_childViewControllerForHomeIndicatorAutoHidden]; +} + - (void)_ln_setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated { [self _ln_setNavigationBarHidden:hidden animated:animated]; diff --git a/LNPopupController/LNPopupController/Private/_LNPopupAddressInfo.h b/LNPopupController/LNPopupController/Private/_LNPopupAddressInfo.h new file mode 100644 index 0000000..ca7ea14 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupAddressInfo.h @@ -0,0 +1,24 @@ +// +// _LNPopupAddressInfo.h +// LNPopupController +// +// Created by Léo Natan on 2024-08-09. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupAddressInfo : NSObject + +- (instancetype)initWithAddress:(NSUInteger)address; + +@property (nonatomic, readonly) NSUInteger address; +@property (nonatomic, copy, readonly) NSString* image; +@property (nonatomic, copy, readonly) NSString* symbol; +@property (nonatomic, readonly) NSUInteger offset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupAddressInfo.mm b/LNPopupController/LNPopupController/Private/_LNPopupAddressInfo.mm new file mode 100644 index 0000000..2e9ccfb --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupAddressInfo.mm @@ -0,0 +1,86 @@ +// +// _LNPopupAddressInfo.mm +// LNPopupController +// +// Created by Léo Natan on 2024-08-09. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupAddressInfo.h" +#include +#include + +@implementation _LNPopupAddressInfo +{ + Dl_info _info; +} + +@synthesize image, symbol, offset, address; + +- (instancetype)initWithAddress:(NSUInteger)_address +{ + self = [super init]; + + if(self) + { + address = _address; + dladdr((void*)address, &_info); + } + + return self; +} + +- (NSString *)image +{ + if(_info.dli_fname != NULL) + { + NSString* potentialImage = [NSString stringWithUTF8String:_info.dli_fname]; + + if([potentialImage containsString:@"/"]) + { + return potentialImage.lastPathComponent; + } + } + + return @"???"; +} + +- (NSString *)symbol +{ + if(_info.dli_sname != NULL) + { + return [NSString stringWithUTF8String:_info.dli_sname]; + } + else if(_info.dli_fname != NULL) + { + return self.image; + } + + return [NSString stringWithFormat:@"0x%1lx", (unsigned long)_info.dli_saddr]; +} + +- (NSUInteger)offset +{ + NSString* str = nil; + if(_info.dli_sname != NULL && (str = [NSString stringWithUTF8String:_info.dli_sname]) != nil) + { + return address - (NSUInteger)_info.dli_saddr; + } + else if(_info.dli_fname != NULL && (str = [NSString stringWithUTF8String:_info.dli_fname]) != nil) + { + return address - (NSUInteger)_info.dli_fbase; + } + + return address - (NSUInteger)_info.dli_saddr; +} + +- (NSString*)description +{ +#if __LP64__ + return [NSString stringWithFormat:@"%-35s 0x%016llx %@ + %ld", self.image.UTF8String, (uint64_t)address, self.symbol, self.offset]; +#else + return [NSString stringWithFormat:@"%-35s 0x%08lx %@ + %d", self.image.UTF8String, (unsigned long)address, self.symbol, self.offset]; +#endif +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.h b/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.h index 3e57086..896bea7 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.h +++ b/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.h @@ -2,8 +2,8 @@ // _LNPopupBackgroundShadowView.h // LNPopupController // -// Created by Leo Natan on 24/09/2023. -// Copyright © 2023 Leo Natan. All rights reserved. +// Created by Léo Natan on 2023-09-25. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.m b/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.m index 4e035dc..b3b5fae 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.m +++ b/LNPopupController/LNPopupController/Private/_LNPopupBackgroundShadowView.m @@ -2,8 +2,8 @@ // _LNPopupBackgroundShadowView.m // LNPopupController // -// Created by Leo Natan on 24/09/2023. -// Copyright © 2023 Leo Natan. All rights reserved. +// Created by Léo Natan on 2023-09-25. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "_LNPopupBackgroundShadowView.h" @@ -11,7 +11,6 @@ @implementation _LNPopupBackgroundShadowView { CAShapeLayer* _maskLayer; - UIColor* _color; } - (instancetype)initWithFrame:(CGRect)frame diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBarAppearanceLegacySupport.h b/LNPopupController/LNPopupController/Private/_LNPopupBarAppearanceLegacySupport.h index ad4bc21..348e9a7 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupBarAppearanceLegacySupport.h +++ b/LNPopupController/LNPopupController/Private/_LNPopupBarAppearanceLegacySupport.h @@ -6,7 +6,7 @@ // Copyright © 2024 Leo Natan. All rights reserved. // -@import UIKit; +#import NS_ASSUME_NONNULL_BEGIN diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.h b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.h index dc13fe7..516dda0 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.h +++ b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.h @@ -2,11 +2,11 @@ // _LNPopupBarBackgroundMaskView.h // LNPopupController // -// Created by Leo Natan on 27/09/2023. -// Copyright © 2023 Leo Natan. All rights reserved. +// Created by Léo Natan on 2023-09-27. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // -@import UIKit; +#import NS_ASSUME_NONNULL_BEGIN diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.m b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.m index c3bfeeb..636160f 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.m +++ b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundMaskView.m @@ -2,8 +2,8 @@ // _LNPopupBarBackgroundMaskView.m // LNPopupController // -// Created by Leo Natan on 27/09/2023. -// Copyright © 2023 Leo Natan. All rights reserved. +// Created by Léo Natan on 2023-09-27. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "_LNPopupBarBackgroundMaskView.h" @@ -132,7 +132,6 @@ static CGGradientRef _LNGradientCreateWithEaseFunction(EASE_FUNC func, UIColor* - (void)setWantsCutout:(BOOL)wantsCutout animated:(BOOL)animated { _wantsCutout = wantsCutout; -// _wantsCutout = NO; _targetAlpha = _wantsCutout ? 0.0 : 1.0; if(animated == NO || self.superview.alpha == 0.0 || self.superview.isHidden) @@ -183,7 +182,7 @@ static CGGradientRef _LNGradientCreateWithEaseFunction(EASE_FUNC func, UIColor* CGContextSetBlendMode(ctx, kCGBlendModeDestinationIn); [[UIColor.blackColor colorWithAlphaComponent:_currentAlpha] setFill]; - [[UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.floatingFrame, 1, 1) cornerRadius:self.floatingCornerRadius] fill]; + [[UIBezierPath bezierPathWithRoundedRect:self.floatingFrame cornerRadius:self.floatingCornerRadius] fill]; UIGraphicsPopContext(); } diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.h b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.h index e3ec3b5..a701c39 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.h +++ b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.h @@ -2,8 +2,8 @@ // _LNPopupBarBackgroundView.h // LNPopupController // -// Created by Leo Natan on 6/26/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-06-20. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.m b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.m index 9f08d30..226f149 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.m +++ b/LNPopupController/LNPopupController/Private/_LNPopupBarBackgroundView.m @@ -2,8 +2,8 @@ // _LNPopupBarBackgroundView.m // LNPopupController // -// Created by Leo Natan on 6/26/21. -// Copyright © 2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2021-06-20. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "_LNPopupBarBackgroundView.h" @@ -173,11 +173,14 @@ _cornerRadius = cornerRadius; self.layer.cornerRadius = cornerRadius; - _effectView.layer.cornerRadius = cornerRadius; - - if (@available(iOS 13.0, *)) + if(@available(iOS 13.0, *)) { self.layer.cornerCurve = kCACornerCurveContinuous; + } + + _effectView.layer.cornerRadius = cornerRadius; + if(@available(iOS 13.0, *)) + { _effectView.layer.cornerCurve = kCACornerCurveContinuous; } } diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBarShadowedImageView.h b/LNPopupController/LNPopupController/Private/_LNPopupBarShadowedImageView.h deleted file mode 100644 index ae70dab..0000000 --- a/LNPopupController/LNPopupController/Private/_LNPopupBarShadowedImageView.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// _LNPopupBarShadowedImageView.h -// LNPopupController -// -// Created by Leo Natan on 15/10/2023. -// Copyright © 2023 Leo Natan. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface _LNPopupBarShadowedImageView : UIImageView - -@property (nonatomic, assign) CGFloat cornerRadius; -@property (nonatomic, copy) NSShadow* shadow; - -@end - -NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBarShadowedImageView.m b/LNPopupController/LNPopupController/Private/_LNPopupBarShadowedImageView.m deleted file mode 100644 index 8d8620b..0000000 --- a/LNPopupController/LNPopupController/Private/_LNPopupBarShadowedImageView.m +++ /dev/null @@ -1,86 +0,0 @@ -// -// _LNPopupBarShadowedImageView.m -// LNPopupController -// -// Created by Leo Natan on 15/10/2023. -// Copyright © 2023 Leo Natan. All rights reserved. -// - -#import "_LNPopupBarShadowedImageView.h" -#import "_LNPopupBackgroundShadowView.h" - -@implementation _LNPopupBarShadowedImageView -{ - _LNPopupBackgroundShadowView* _shadowView; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - - if(self) - { - _shadowView = [_LNPopupBackgroundShadowView new]; - } - - return self; -} - -- (void)setShadow:(NSShadow *)shadow -{ - _shadow = [shadow copy]; - - _shadowView.shadow = shadow; -} - -- (void)didMoveToSuperview -{ - if(self.superview) - { - [self _updateShadowViewFrame]; - } - else - { - [_shadowView removeFromSuperview]; - } -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - [self _updateShadowViewFrame]; -} - -- (void)setBounds:(CGRect)bounds -{ - [super setBounds:bounds]; - [self _updateShadowViewFrame]; -} - -- (void)setCenter:(CGPoint)center -{ - [super setCenter:center]; - [self _updateShadowViewFrame]; -} - -- (void)_updateShadowViewFrame -{ - [self.superview insertSubview:_shadowView aboveSubview:self]; - _shadowView.frame = self.frame; -} - -- (void)setCornerRadius:(CGFloat)cornerRadius -{ - _cornerRadius = cornerRadius; - self.layer.cornerRadius = cornerRadius; - _shadowView.cornerRadius = cornerRadius; -} - -- (void)setHidden:(BOOL)hidden -{ - [super setHidden:hidden]; - - _shadowView.hidden = hidden; -} - -@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupBase64Utils.hh b/LNPopupController/LNPopupController/Private/_LNPopupBase64Utils.hh new file mode 100644 index 0000000..13d2c1b --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupBase64Utils.hh @@ -0,0 +1,75 @@ +// +// _LNPopupBase64Utils.hh +// LNPopupController +// +// Created by Léo Natan on 2024-09-01. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import +#include +#include + +namespace lnpopup { + +template +struct base64_string : std::array { + consteval base64_string(const char (&input)[N]) : base64_string(input, std::make_index_sequence{}) {} + template + consteval base64_string(const char (&input)[N], std::index_sequence) : std::array{ input[Is]... } {} +}; + +template +consteval const auto base64_encode(const char(&input)[N]) { + constexpr char encoding_table[] = + { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + constexpr size_t out_len = 4 * (((N - 1) + 2) / 3) + 1; + + size_t in_len = N - 1; + char output[out_len] {0}; + size_t i = 0; + char *p = const_cast(output); + + for(i = 0; in_len > 2 && i < in_len - 2; i += 3) + { + *p++ = encoding_table[(input[i] >> 2) & 0x3F]; + *p++ = encoding_table[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)]; + *p++ = encoding_table[((input[i + 1] & 0xF) << 2) | ((int)(input[i + 2] & 0xC0) >> 6)]; + *p++ = encoding_table[input[i + 2] & 0x3F]; + } + + if(i < in_len) + { + *p++ = encoding_table[(input[i] >> 2) & 0x3F]; + if(i == (in_len - 1)) + { + *p++ = encoding_table[((input[i] & 0x3) << 4)]; + *p++ = '='; + } + else + { + *p++ = encoding_table[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)]; + *p++ = encoding_table[((input[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + return base64_string(output); +} + +CF_INLINE +auto decode_hidden_string(auto encoded) +{ + return [[NSString alloc] initWithData:[[NSData alloc] initWithBase64EncodedString:@(encoded.data()) options:0] encoding:NSUTF8StringEncoding]; +} + +} //namespace lnpopup + +#define LNPopupHiddenString(input) (lnpopup::decode_hidden_string(lnpopup::base64_encode("" input ""))) diff --git a/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.h b/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.h index ab59f8c..d9f5504 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.h +++ b/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.h @@ -2,14 +2,16 @@ // _LNPopupSwizzlingUtils.h // LNPopupController // -// Created by Leo Natan on 1/14/18. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2020-07-31. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import -@import ObjectiveC; +#import #import +CF_EXTERN_C_BEGIN + #define unavailable(...) @available(__VA_ARGS__)) { } else if(YES #define LNSwizzleComplain(FORMAT, ...) \ @@ -20,11 +22,11 @@ raise(SIGTRAP); \ } #ifndef LNAlwaysInline -#define LNAlwaysInline inline __attribute__((__always_inline__)) +#define LNAlwaysInline CF_INLINE #endif /* LNAlwaysInline */ LNAlwaysInline -static BOOL LNSwizzleMethod(Class cls, SEL orig, SEL alt) +BOOL LNSwizzleMethod(Class cls, SEL orig, SEL alt) { static BOOL shouldTrapAndPrint = NO; static dispatch_once_t onceToken; @@ -52,13 +54,13 @@ static BOOL LNSwizzleMethod(Class cls, SEL orig, SEL alt) } LNAlwaysInline -static BOOL LNSwizzleClassMethod(Class cls, SEL orig, SEL alt) +BOOL LNSwizzleClassMethod(Class cls, SEL orig, SEL alt) { return LNSwizzleMethod(object_getClass((id)cls), orig, alt); } LNAlwaysInline -static void __LNCopyMethods(Class orig, Class target) +void __LNCopyMethods(Class orig, Class target) { //Copy class methods Class targetMetaclass = object_getClass(target); @@ -91,7 +93,7 @@ static void __LNCopyMethods(Class orig, Class target) } LNAlwaysInline -static BOOL LNDynamicallySubclass(id obj, Class target) +BOOL LNDynamicallySubclass(id obj, Class target) { if(obj == nil) { @@ -131,7 +133,7 @@ static BOOL LNDynamicallySubclass(id obj, Class target) } LNAlwaysInline -static Class LNDynamicSubclassSuper(id obj, Class dynamic) +Class LNDynamicSubclassSuper(id obj, Class dynamic) { NSMutableDictionary* superRegistrar = objc_getAssociatedObject(obj, (void*)&objc_setAssociatedObject); Class cls = superRegistrar[NSStringFromClass(dynamic)]; @@ -143,6 +145,6 @@ static Class LNDynamicSubclassSuper(id obj, Class dynamic) return cls; } - -NSString* _LNPopupDecodeBase64String(NSString* base64String); NSArray* _LNPopupGetPropertyNames(Class cls, NSArray* excludedProperties); + +CF_EXTERN_C_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.m b/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.m index 3438589..ebe681d 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.m +++ b/LNPopupController/LNPopupController/Private/_LNPopupSwizzlingUtils.m @@ -2,18 +2,13 @@ // _LNPopupSwizzlingUtils.m // LNPopupController // -// Created by Leo Natan on 1/14/18. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2018-01-15. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "_LNPopupSwizzlingUtils.h" @import ObjectiveC; -NSString* _LNPopupDecodeBase64String(NSString* base64String) -{ - return [[NSString alloc] initWithData:[[NSData alloc] initWithBase64EncodedString:base64String options:0] encoding:NSUTF8StringEncoding]; -} - NSArray* _LNPopupGetPropertyNames(Class cls, NSArray* excludedProperties) { unsigned int propertyCount = 0; diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionAnimator.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionAnimator.h new file mode 100644 index 0000000..612c55d --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionAnimator.h @@ -0,0 +1,56 @@ +// +// _LNPopupTransitionAnimator.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import +#import +#import +#import +#import "_LNPopupTransitionView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface UIViewPropertyAnimator () + +- (void)addAnimations:(void (^)(void))animation delayFactor:(CGFloat)delayFactor durationFactor:(CGFloat)durationFactor; + +@end + +@interface _LNPopupTransitionAnimator : NSObject + +- (instancetype)initWithTransitionView:(nullable _LNPopupTransitionView*)transitionView userView:(UIView*)view popupBar:(LNPopupBar*)popupBar popupContentView:(LNPopupContentView*)popupContentView; + +@property (nonatomic, strong, readonly) UIView* view; +@property (nonatomic, strong, readonly) LNPopupBar* popupBar; +@property (nonatomic, strong, readonly) LNPopupContentView* popupContentView; + +@property (nonatomic, strong, readonly, nullable) _LNPopupTransitionView* transitionView; +@property (nonatomic, strong, readonly, nullable) UIView* crossfadeView; +@property (nonatomic, readonly) CGRect sourceFrame; +@property (nonatomic, readonly) CGRect targetFrame; +@property (nonatomic, readonly) CGAffineTransform transform; + +@property (nonatomic, readonly) CGFloat scaledBarImageViewCornerRadius; +@property (nonatomic, strong, readonly) NSShadow* scaledBarImageViewShadow; + +- (void)animateWithAnimator:(UIViewPropertyAnimator*)animator otherAnimations:(void(^)(void))otherAnimations NS_REQUIRES_SUPER; +- (void)beforeAnyAnimation NS_REQUIRES_SUPER; +- (void)performBeforeAdditionalAnimations NS_REQUIRES_SUPER; +- (void)performAdditionalAnimations NS_REQUIRES_SUPER; +- (void)performAdditionalDelayed015Animations NS_REQUIRES_SUPER; +- (void)performAdditionalDelayed05Animations NS_REQUIRES_SUPER; +- (void)performAdditional01Animations NS_REQUIRES_SUPER; +- (void)performAdditional075Animations NS_REQUIRES_SUPER; +- (void)performAdditional04Delayed015Animations NS_REQUIRES_SUPER; +- (void)performAdditional075Delayed015Animations NS_REQUIRES_SUPER; +- (void)performAdditionalCompletion NS_REQUIRES_SUPER; + +@property (nonatomic, readonly) LNPopupPresentationState targetState; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionAnimator.mm b/LNPopupController/LNPopupController/Private/_LNPopupTransitionAnimator.mm new file mode 100644 index 0000000..5240639 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionAnimator.mm @@ -0,0 +1,213 @@ +// +// _LNPopupTransitionAnimatorOpen.mm +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionAnimator.h" +#import "LNPopupBar+Private.h" +#import +#import + +static const void* _LNPopupOpenCloseTransitionViewKey = &_LNPopupOpenCloseTransitionViewKey; + +@implementation _LNPopupTransitionAnimator + +- (instancetype)initWithTransitionView:(_LNPopupTransitionView *)transitionView userView:(UIView *)view popupBar:(LNPopupBar *)popupBar popupContentView:(LNPopupContentView *)popupContentView +{ + self = [super init]; + + if(self) + { + _transitionView = transitionView; + _view = view; + _popupBar = popupBar; + _popupContentView = popupContentView; + } + + return self; +} + +- (void)animateWithAnimator:(UIViewPropertyAnimator *)animator otherAnimations:(void (^)(void))otherAnimations +{ + static SEL transitionWillBegin = NSSelectorFromString(@"_transitionWillBeginToState:"); + static SEL transitionDidEnd = NSSelectorFromString(@"_transitionDidEnd"); + + [UIView performWithoutAnimation:^{ + [self.popupContentView layoutIfNeeded]; + self.popupBar.imageView.alpha = 0.0; + + if(self.transitionView == nil) + { + _transitionView = [[_LNPopupTransitionView alloc] initWithSourceView:self.view]; + } + + UIImage* image; + if(@available(iOS 13, *)) + { + if(self.popupBar.swiftuiImageController != nil) + { + id contents = self.popupBar.swiftuiImageController.view.subviews.firstObject.layer.contents; + if(contents != nil && CFGetTypeID((__bridge CFTypeRef)contents) == CGImageGetTypeID()) + { + image = [[UIImage alloc] initWithCGImage:(__bridge CGImageRef)contents]; + } + else + { + image = [[[UIGraphicsImageRenderer alloc] initWithSize:self.popupBar.imageView.bounds.size] imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) { + [self.popupBar.imageView drawViewHierarchyInRect:self.popupBar.imageView.bounds afterScreenUpdates:NO]; + }]; + } + } + else + { + image = self.popupBar.imageView.image; + } + } + else + { + image = self.popupBar.imageView.image; + } + + _crossfadeView = [[LNPopupImageView alloc] initWithImage:image]; + _crossfadeView.contentMode = self.popupBar.imageView.contentMode; + _crossfadeView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _crossfadeView.frame = _transitionView.bounds; + [_transitionView addSubview:_crossfadeView]; + + _transitionView.frame = self.sourceFrame; + [self beforeAnyAnimation]; + + objc_setAssociatedObject(self.transitionView.sourceView, _LNPopupOpenCloseTransitionViewKey, _transitionView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + }]; + + [animator addAnimations:otherAnimations]; + + [animator addAnimations:^{ + [UIView performWithoutAnimation:^{ + [self.popupContentView.window addSubview:_transitionView]; + [self performBeforeAdditionalAnimations]; + }]; + + [self performAdditionalAnimations]; + + if([self.view respondsToSelector:transitionWillBegin]) + { + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:[self.view methodSignatureForSelector:transitionWillBegin]]; + invocation.target = self.view; + LNPopupPresentationState targetState = self.targetState; + invocation.selector = transitionWillBegin; + [invocation setArgument:&targetState atIndex:2]; + [invocation invoke]; + } + }]; + + [animator addAnimations:^{ + [UIView animateKeyframesWithDuration:0.0 delay:0.0 options:0 animations:^{ + [UIView addKeyframeWithRelativeStartTime:0.15 relativeDuration:0.85 animations:^{ + [self performAdditionalDelayed015Animations]; + }]; + } completion:nil]; + }]; + + [animator addAnimations:^{ + [UIView animateKeyframesWithDuration:0.0 delay:0.0 options:0 animations:^{ + [UIView addKeyframeWithRelativeStartTime:0.15 relativeDuration:0.4 animations:^{ + [self performAdditional04Delayed015Animations]; + }]; + } completion:nil]; + }]; + + [animator addAnimations:^{ + [self performAdditionalDelayed05Animations]; + } delayFactor:0.5]; + + [animator addAnimations:^{ + [UIView animateKeyframesWithDuration:0.0 delay:0.0 options:0 animations:^{ + [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.75 animations:^{ + [self performAdditional075Animations]; + }]; + } completion:nil]; + } delayFactor:0.0]; + + [animator addAnimations:^{ + [UIView animateKeyframesWithDuration:0.0 delay:0.0 options:0 animations:^{ + [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.1 animations:^{ + [self performAdditional01Animations]; + }]; + } completion:nil]; + } delayFactor:0.0]; + + [animator addAnimations:^{ + [UIView animateKeyframesWithDuration:0.0 delay:0.0 options:0 animations:^{ + [UIView addKeyframeWithRelativeStartTime:0.15 relativeDuration:0.75 animations:^{ + [self performAdditional075Delayed015Animations]; + }]; + } completion:nil]; + } delayFactor:0.0]; + + [animator addCompletion:^(UIViewAnimatingPosition finalPosition) { + if([self.view respondsToSelector:transitionDidEnd]) + { + [self.view performSelector:transitionDidEnd]; + } + + [self completeTransition]; + }]; +} + +- (CGRect)sourceFrame +{ + return CGRectZero; +} + +- (CGRect)targetFrame +{ + return CGRectZero; +} + +- (CGAffineTransform)transform +{ + return CGAffineTransformIdentity; +} + +- (CGFloat)scaledBarImageViewCornerRadius +{ + return 0.0; +} + +- (NSShadow *)scaledBarImageViewShadow +{ + return nil; +} + +- (LNPopupPresentationState)targetState +{ + return (LNPopupPresentationState)-1; +} + +- (void)beforeAnyAnimation {} +- (void)performBeforeAdditionalAnimations {} +- (void)performAdditionalAnimations {} +- (void)performAdditionalDelayed015Animations {} +- (void)performAdditionalDelayed05Animations {} +- (void)performAdditional01Animations {} +- (void)performAdditional075Animations {} +- (void)performAdditional04Delayed015Animations {} +- (void)performAdditional075Delayed015Animations {} +- (void)performAdditionalCompletion {} + +- (void)completeTransition +{ + [UIView performWithoutAnimation:^{ + UIView* transitionView = objc_getAssociatedObject(self.transitionView.sourceView, _LNPopupOpenCloseTransitionViewKey); + [transitionView removeFromSuperview]; + objc_setAssociatedObject(self.transitionView.sourceView, _LNPopupOpenCloseTransitionViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + self.popupBar.imageView.alpha = 1.0; + [self performAdditionalCompletion]; + }]; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionCloseAnimator.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionCloseAnimator.h new file mode 100644 index 0000000..5c56d61 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionCloseAnimator.h @@ -0,0 +1,22 @@ +// +// _LNPopupTransitionCloseAnimator.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionAnimator.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupTransitionCloseAnimator : _LNPopupTransitionAnimator + +- (instancetype)initWithTransitionView:(nullable _LNPopupTransitionView*)transitionView userView:(UIView*)view popupBar:(LNPopupBar*)popupBar popupContentView:(LNPopupContentView*)popupContentView currentContentController:(UIViewController*)currentContentController containerController:(UIViewController*)containerController; + +@property (nonatomic, strong) UIViewController* currentContentController; +@property (nonatomic, strong) UIViewController* containerController; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionCloseAnimator.m b/LNPopupController/LNPopupController/Private/_LNPopupTransitionCloseAnimator.m new file mode 100644 index 0000000..1b97b38 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionCloseAnimator.m @@ -0,0 +1,104 @@ +// +// _LNPopupTransitionCloseAnimator.m +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionCloseAnimator.h" +#import "UIViewController+LNPopupSupportPrivate.h" +#import "LNPopupBar+Private.h" + +@implementation _LNPopupTransitionCloseAnimator + +- (instancetype)initWithTransitionView:(_LNPopupTransitionView *)transitionView userView:(UIView *)view popupBar:(LNPopupBar *)popupBar popupContentView:(LNPopupContentView *)popupContentView currentContentController:(UIViewController *)currentContentController containerController:(UIViewController *)containerController +{ + self = [super initWithTransitionView:transitionView userView:view popupBar:popupBar popupContentView:popupContentView]; + + if(self) + { + self.currentContentController = currentContentController; + self.containerController = containerController; + } + + return self; +} + +- (CGRect)sourceFrame +{ + return [self.popupContentView.window convertRect:self.transitionView.sourceView.bounds fromView:self.transitionView.sourceView]; +} + +- (CGRect)targetFrame +{ + return [self.popupBar.imageView.window convertRect:self.popupBar.imageView.bounds fromView:self.popupBar.imageView]; +} + +- (CGFloat)scaledBarImageViewCornerRadius +{ + return MAX(self.popupBar.imageView.cornerRadius * self.sourceFrame.size.width / self.popupBar.imageView.bounds.size.width, self.popupBar.imageView.cornerRadius * self.sourceFrame.size.height / self.popupBar.imageView.bounds.size.height); +} + +- (NSShadow *)scaledBarImageViewShadow +{ + NSShadow* scaled = self.popupBar.imageView.shadow.copy; + scaled.shadowBlurRadius = scaled.shadowBlurRadius * self.sourceFrame.size.width / self.popupBar.imageView.bounds.size.width; + return scaled; +} + +- (LNPopupPresentationState)targetState +{ + return LNPopupPresentationStateBarPresented; +} + +- (void)beforeAnyAnimation +{ + [super beforeAnyAnimation]; + + self.crossfadeView.alpha = 0.0; + self.crossfadeView.cornerRadius = self.transitionView.cornerRadius; +} + +- (void)performAdditionalAnimations +{ + [super performAdditionalAnimations]; + + [self.transitionView setTargetFrameUpdatingTransform:self.targetFrame]; + + self.crossfadeView.cornerRadius = self.popupBar.imageView.cornerRadius; +} + +- (void)performAdditionalDelayed015Animations +{ + [super performAdditionalDelayed015Animations]; + + if(self.containerController._ln_shouldPopupContentAnyFadeForTransition) + { + if(self.containerController._ln_shouldPopupContentViewFadeForTransition) + { + self.popupContentView.alpha = 0.0; + } + else + { + self.currentContentController.view.alpha = 0.0; + } + } +} + +- (void)performAdditional04Delayed015Animations +{ + [super performAdditional04Delayed015Animations]; + + self.crossfadeView.alpha = 1.0; +} + +- (void)performAdditionalCompletion +{ + [super performAdditionalCompletion]; + + self.popupContentView.alpha = 1.0; + self.currentContentController.view.alpha = 1.0; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericCloseAnimator.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericCloseAnimator.h new file mode 100644 index 0000000..46e3ae6 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericCloseAnimator.h @@ -0,0 +1,17 @@ +// +// _LNPopupTransitionGenericCloseAnimator.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionCloseAnimator.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupTransitionGenericCloseAnimator : _LNPopupTransitionCloseAnimator + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericCloseAnimator.m b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericCloseAnimator.m new file mode 100644 index 0000000..614418f --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericCloseAnimator.m @@ -0,0 +1,45 @@ +// +// _LNPopupTransitionGenericCloseAnimator.m +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionGenericCloseAnimator.h" + +@implementation _LNPopupTransitionGenericCloseAnimator +{ + NSShadow* _targetShadow; +} + +- (void)animateWithAnimator:(UIViewPropertyAnimator *)animator otherAnimations:(void (^)(void))otherAnimations +{ + [super animateWithAnimator:animator otherAnimations:otherAnimations]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((animator.duration * 0.38) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [animator addAnimations:^{ + self.transitionView.cornerRadius = self.popupBar.imageView.cornerRadius; + }]; + }); +} + +- (void)beforeAnyAnimation +{ + [super beforeAnyAnimation]; + + _targetShadow = self.popupBar.imageView.shadow.copy; + + NSShadow* hiddenShadow = [_targetShadow copy]; + hiddenShadow.shadowColor = [_targetShadow.shadowColor colorWithAlphaComponent:0.0]; + self.transitionView.shadow = hiddenShadow; +} + +- (void)performAdditionalAnimations +{ + [super performAdditionalAnimations]; + + self.transitionView.shadow = _targetShadow; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericOpenAnimator.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericOpenAnimator.h new file mode 100644 index 0000000..d13eb03 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericOpenAnimator.h @@ -0,0 +1,17 @@ +// +// _LNPopupTransitionGenericOpenAnimator.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionOpenAnimator.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupTransitionGenericOpenAnimator : _LNPopupTransitionOpenAnimator + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericOpenAnimator.m b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericOpenAnimator.m new file mode 100644 index 0000000..f7ae2bb --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionGenericOpenAnimator.m @@ -0,0 +1,35 @@ +// +// _LNPopupTransitionGenericOpenAnimator.m +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionGenericOpenAnimator.h" + +@implementation _LNPopupTransitionGenericOpenAnimator +{ + NSShadow* _targetShadow; +} + +- (void)beforeAnyAnimation +{ + [super beforeAnyAnimation]; + + self.transitionView.shadow = self.popupBar.imageView.shadow.copy; + self.transitionView.cornerRadius = self.scaledBarImageViewCornerRadius; + + _targetShadow = [self.transitionView.shadow copy]; + _targetShadow.shadowColor = [_targetShadow.shadowColor colorWithAlphaComponent:0.0]; +} + +- (void)performAdditionalAnimations +{ + [super performAdditionalAnimations]; + + self.transitionView.shadow = _targetShadow; + self.transitionView.cornerRadius = 0.0; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionOpenAnimator.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionOpenAnimator.h new file mode 100644 index 0000000..b714777 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionOpenAnimator.h @@ -0,0 +1,21 @@ +// +// _LNPopupTransitionOpenAnimator.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import +#import "_LNPopupTransitionAnimator.h" +#import +#import +#import "_LNPopupTransitionView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupTransitionOpenAnimator : _LNPopupTransitionAnimator + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionOpenAnimator.m b/LNPopupController/LNPopupController/Private/_LNPopupTransitionOpenAnimator.m new file mode 100644 index 0000000..027cb48 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionOpenAnimator.m @@ -0,0 +1,79 @@ +// +// _LNPopupTransitionOpenAnimator.m +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionOpenAnimator.h" +#import + +@implementation _LNPopupTransitionOpenAnimator + +- (CGRect)sourceFrame +{ + return [self.popupBar.imageView.window convertRect:self.popupBar.imageView.bounds fromView:self.popupBar.imageView]; +} + +- (CGRect)targetFrame +{ + return [self.popupContentView.window convertRect:self.transitionView.sourceView.bounds fromView:self.transitionView.sourceView];; +} + +- (CGAffineTransform)transform +{ + CGFloat ratioX = self.sourceFrame.size.width / self.targetFrame.size.width; + CGFloat ratioY = self.sourceFrame.size.height / self.targetFrame.size.height; + return CGAffineTransformMakeScale(ratioX, ratioY); +} + +- (CGFloat)scaledBarImageViewCornerRadius +{ + return self.popupBar.imageView.cornerRadius * self.targetFrame.size.width / self.popupBar.imageView.bounds.size.width; +} + +- (NSShadow *)scaledBarImageViewShadow +{ + NSShadow* scaled = self.popupBar.imageView.shadow.copy; + scaled.shadowBlurRadius = scaled.shadowBlurRadius * self.targetFrame.size.width / self.popupBar.imageView.bounds.size.width; + return scaled; +} + +- (LNPopupPresentationState)targetState +{ + return LNPopupPresentationStateOpen; +} + +- (void)beforeAnyAnimation +{ + [super beforeAnyAnimation]; + + self.crossfadeView.alpha = 1.0; + self.crossfadeView.cornerRadius = self.popupBar.imageView.cornerRadius; +} + +- (void)performBeforeAdditionalAnimations +{ + [super performBeforeAdditionalAnimations]; + + self.transitionView.sourceViewTransform = self.transform; +} + +- (void)performAdditionalAnimations +{ + [super performAdditionalAnimations]; + + self.transitionView.frame = self.targetFrame; + self.transitionView.sourceViewTransform = CGAffineTransformIdentity; + self.crossfadeView.cornerRadius = self.transitionView.cornerRadius; +} + +- (void)performAdditional01Animations +{ + [super performAdditional01Animations]; + + self.crossfadeView.alpha = 0.0; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredCloseAnimator.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredCloseAnimator.h new file mode 100644 index 0000000..6d8635c --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredCloseAnimator.h @@ -0,0 +1,20 @@ +// +// _LNPopupTransitionPreferredCloseAnimator.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionCloseAnimator.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupTransitionPreferredCloseAnimator : _LNPopupTransitionCloseAnimator + +@property (nonatomic, strong, readonly) UIView* view; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredCloseAnimator.mm b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredCloseAnimator.mm new file mode 100644 index 0000000..4342b49 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredCloseAnimator.mm @@ -0,0 +1,77 @@ +// +// _LNPopupTransitionPreferredCloseAnimator.m +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionPreferredCloseAnimator.h" + +@implementation _LNPopupTransitionPreferredCloseAnimator +{ + CGFloat _originalCornerRadius; + NSShadow* _originalShadow; + BOOL _supportsShadow; +} + +@dynamic view; + +- (void)beforeAnyAnimation +{ + [super beforeAnyAnimation]; + + if([self.view respondsToSelector:@selector(supportsShadow)]) + { + _supportsShadow = self.view.supportsShadow; + } + else + { + _supportsShadow = YES; + } + + _originalCornerRadius = self.view.cornerRadius; + if(_supportsShadow) + { + _originalShadow = self.view.shadow.copy; + } + else + { + _originalShadow = nil; + } + + self.crossfadeView.cornerRadius = self.view.cornerRadius; +} + +- (void)performAdditionalAnimations +{ + [super performAdditionalAnimations]; + + self.view.cornerRadius = self.scaledBarImageViewCornerRadius; + self.crossfadeView.cornerRadius = self.popupBar.imageView.cornerRadius; + if(_supportsShadow) + { + self.view.shadow = self.scaledBarImageViewShadow; + } + else + { + self.transitionView.shadow = self.popupBar.imageView.shadow.copy; + } +} + +- (void)performAdditionalCompletion +{ + self.view.cornerRadius = _originalCornerRadius; + if(_supportsShadow) + { + self.view.shadow = _originalShadow; + } + else + { + self.transitionView.shadow = _originalShadow; + } + + [super performAdditionalCompletion]; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredOpenAnimator.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredOpenAnimator.h new file mode 100644 index 0000000..517824e --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredOpenAnimator.h @@ -0,0 +1,20 @@ +// +// _LNPopupTransitionPreferredOpenAnimator.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionOpenAnimator.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupTransitionPreferredOpenAnimator : _LNPopupTransitionOpenAnimator + +@property (nonatomic, strong, readonly) UIView* view; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredOpenAnimator.mm b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredOpenAnimator.mm new file mode 100644 index 0000000..5677787 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionPreferredOpenAnimator.mm @@ -0,0 +1,73 @@ +// +// _LNPopupTransitionPreferredOpenAnimator.m +// LNPopupController +// +// Created by Léo Natan on 2025-03-24. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionPreferredOpenAnimator.h" + +@implementation _LNPopupTransitionPreferredOpenAnimator +{ + CGFloat _originalCornerRadius; + NSShadow* _originalShadow; + BOOL _supportsShadow; +} + +@dynamic view; + +- (void)beforeAnyAnimation +{ + [super beforeAnyAnimation]; + + if([self.view respondsToSelector:@selector(supportsShadow)]) + { + _supportsShadow = self.view.supportsShadow; + } + else + { + _supportsShadow = YES; + } + + _originalCornerRadius = self.view.cornerRadius; + if(_supportsShadow) + { + _originalShadow = self.view.shadow.copy; + } + else + { + _originalShadow = nil; + } + + self.view.cornerRadius = self.scaledBarImageViewCornerRadius; + if(_supportsShadow) + { + self.view.shadow = self.scaledBarImageViewShadow; + } + else + { + self.transitionView.shadow = self.popupBar.imageView.shadow.copy; + } +} + +- (void)performAdditionalAnimations +{ + [super performAdditionalAnimations]; + + self.view.cornerRadius = _originalCornerRadius; + self.view.shadow = _originalShadow; + + if(_supportsShadow) + { + self.view.shadow = _originalShadow; + } + else + { + self.transitionView.shadow = _originalShadow; + } + + self.crossfadeView.cornerRadius = self.view.cornerRadius; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionView.h b/LNPopupController/LNPopupController/Private/_LNPopupTransitionView.h new file mode 100644 index 0000000..be95304 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionView.h @@ -0,0 +1,32 @@ +// +// _LNPopupTransitionView.h +// LNPopupController +// +// Created by Léo Natan on 2025-03-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface _LNPopupTransitionView : UIView + ++ (instancetype)transitionViewWithSourceView:(UIView*)sourceView; + +- (instancetype)initWithSourceView:(UIView*)sourceView; + +- (void)setTargetFrameUpdatingTransform:(CGRect)targetFrame; + +@property (nonatomic, strong, readonly) UIView* sourceView; + +@property (nonatomic, copy) NSShadow* shadow; +@property (nonatomic, assign) CGFloat cornerRadius; +@property (nonatomic, assign) BOOL layerAlwaysMasksToBounds; + +@property (nonatomic, assign) CGAffineTransform sourceViewTransform; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupController/LNPopupController/Private/_LNPopupTransitionView.mm b/LNPopupController/LNPopupController/Private/_LNPopupTransitionView.mm new file mode 100644 index 0000000..55ad5d9 --- /dev/null +++ b/LNPopupController/LNPopupController/Private/_LNPopupTransitionView.mm @@ -0,0 +1,119 @@ +// +// _LNPopupTransitionView.mm +// LNPopupController +// +// Created by Léo Natan on 2025-03-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "_LNPopupTransitionView.h" +#import "_LNPopupBase64Utils.hh" + +@implementation _LNPopupTransitionView +{ + UIView* _portalView; + UIView* _radiusContainerView; +} + ++ (instancetype)transitionViewWithSourceView:(UIView*)sourceView +{ + return [[self alloc] initWithSourceView:sourceView]; +} + +- (instancetype)initWithSourceView:(UIView*)sourceView +{ + self = [super initWithFrame:CGRectZero]; + + if(self) + { + _sourceView = sourceView; + + _portalView = [[NSClassFromString(LNPopupHiddenString("_UIPortalView")) alloc] initWithFrame:CGRectZero]; + _portalView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [_portalView setValue:sourceView forKey:LNPopupHiddenString("sourceView")]; + [_portalView setValue:@YES forKey:LNPopupHiddenString("hidesSourceView")]; + [_portalView setValue:@YES forKey:LNPopupHiddenString("matchesTransform")]; + _portalView.layer.contentsGravity = kCAGravityResize; + + _radiusContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + _radiusContainerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + if(@available(iOS 13.0, *)) + { + _radiusContainerView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.cornerRadius = 0.0; + + [_radiusContainerView addSubview:_portalView]; + [self addSubview:_radiusContainerView]; + + _layerAlwaysMasksToBounds = NO; + + self.layer.masksToBounds = NO; + } + + return self; +} + +- (CGFloat)cornerRadius +{ + return _radiusContainerView.layer.cornerRadius; +} + +- (void)setCornerRadius:(CGFloat)cornerRadius +{ + _radiusContainerView.layer.cornerRadius = cornerRadius; + _radiusContainerView.layer.masksToBounds = _layerAlwaysMasksToBounds || cornerRadius != 0.0; +} + +- (void)setLayerAlwaysMasksToBounds:(BOOL)layerAlwaysMasksToBounds +{ + _layerAlwaysMasksToBounds = layerAlwaysMasksToBounds; + self.cornerRadius = self.cornerRadius; +} + +- (void)setTargetFrameUpdatingTransform:(CGRect)targetFrame +{ + CGRect sourceFrame = self.frame; + + [super setFrame:targetFrame]; + + CGFloat ratioX = targetFrame.size.width / sourceFrame.size.width; + CGFloat ratioY = targetFrame.size.height / sourceFrame.size.height; + [self setSourceViewTransform: CGAffineTransformMakeScale(ratioX, ratioY)]; +} + +- (void)setShadow:(NSShadow *)shadow +{ + _shadow = shadow; + + self.layer.shadowOffset = _shadow.shadowOffset; + self.layer.shadowRadius = _shadow.shadowBlurRadius; + + [self _updateShadowColor]; +} + +- (void)_updateShadowColor +{ + self.layer.shadowColor = [(UIColor*)_shadow.shadowColor colorWithAlphaComponent:1.0].CGColor; + self.layer.shadowOpacity = CGColorGetAlpha([_shadow.shadowColor CGColor]); +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection +{ + [super traitCollectionDidChange:previousTraitCollection]; + + self.layer.rasterizationScale = self.traitCollection.displayScale; + [self _updateShadowColor]; +} + +- (CGAffineTransform)sourceViewTransform +{ + return _portalView.transform; +} + +- (void)setSourceViewTransform:(CGAffineTransform)sourceViewTransform +{ + _portalView.transform = sourceViewTransform; +} + +@end diff --git a/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.h b/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.h index 339d92d..cbf08e8 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.h +++ b/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.h @@ -2,8 +2,8 @@ // _LNPopupUIBarAppearanceProxy.h // LNPopupController // -// Created by Leo Natan on 30/08/2023. -// Copyright © 2023 Leo Natan. All rights reserved. +// Created by Léo Natan on 2023-08-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.m b/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.mm similarity index 76% rename from LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.m rename to LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.mm index b97a79e..e0d48f7 100644 --- a/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.m +++ b/LNPopupController/LNPopupController/Private/_LNPopupUIBarAppearanceProxy.mm @@ -2,30 +2,25 @@ // _LNPopupUIBarAppearanceProxy.m // LNPopupController // -// Created by Leo Natan on 30/08/2023. -// Copyright © 2023 Leo Natan. All rights reserved. +// Created by Léo Natan on 2023-08-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #if ! LNPopupControllerEnforceStrictClean #import "_LNPopupUIBarAppearanceProxy.h" #import "_LNPopupSwizzlingUtils.h" +#import "_LNPopupBase64Utils.hh" -@import UIKit; -@import ObjectiveC; - -//_backgroundData -static NSString* const _bD = @"X2JhY2tncm91bmREYXRh"; -//shadowViewBackgroundColor -static NSString* const _sVBC = @"c2hhZG93Vmlld0JhY2tncm91bmRDb2xvcg=="; -//shadowViewTintColor -static NSString* const _sVTC = @"c2hhZG93Vmlld1RpbnRDb2xvcg=="; +#import +#import static const void* _LNPopupBarBackgroundDataSubclassShadowHandlerKey = &_LNPopupBarBackgroundDataSubclassShadowHandlerKey; -#define LN_ADD_PROPERTY_GETTER(cls, base64Name, impBlock) SEL sel##base64Name = NSSelectorFromString(_LNPopupDecodeBase64String(base64Name)); \ -class_addMethod(cls, sel##base64Name, imp_implementationWithBlock(^id(id _self){ \ -return ((id(^)(id, SEL))impBlock)(_self, sel##base64Name); \ +#define LN_ADD_PROPERTY_GETTER(cls, hiddenString, impBlock) \ +static SEL OS_CONCAT(sel, hiddenString) = NSSelectorFromString(LNPopupHiddenString(OS_STRINGIFY(hiddenString))); \ +class_addMethod(cls, OS_CONCAT(sel, hiddenString), imp_implementationWithBlock(^id(id _self){ \ +return ((id(^)(id, SEL))impBlock)(_self, OS_CONCAT(sel, hiddenString)); \ }), method_getTypeEncoding(class_getInstanceMethod(NSObject.class, @selector(description)))); #define LN_SHADOW_CLEAR_COLOR_OR_SUPER if(self._ln_shouldHideShadow) { \ @@ -33,7 +28,7 @@ return UIColor.clearColor; \ } else { \ Class superclass = LNDynamicSubclassSuper(self, _LNPopupBarBackgroundDataSubclass.class); \ struct objc_super super = {.receiver = self, .super_class = superclass}; \ -id (*super_class)(struct objc_super*, SEL) = (void*)objc_msgSendSuper; \ +id (*super_class)(struct objc_super*, SEL) = reinterpret_cast(objc_msgSendSuper); \ return super_class(&super, _cmd); \ } @@ -42,7 +37,7 @@ return nil; \ } else { \ Class superclass = LNDynamicSubclassSuper(self, _LNPopupBarBackgroundDataSubclass.class); \ struct objc_super super = {.receiver = self, .super_class = superclass}; \ -id (*super_class)(struct objc_super*, SEL) = (void*)objc_msgSendSuper; \ +id (*super_class)(struct objc_super*, SEL) = reinterpret_cast(objc_msgSendSuper); \ return super_class(&super, _cmd); \ } @@ -72,9 +67,9 @@ return super_class(&super, _cmd); \ }; //shadowViewBackgroundColor - LN_ADD_PROPERTY_GETTER(self, _sVBC, imp); + LN_ADD_PROPERTY_GETTER(self, shadowViewBackgroundColor, imp); //shadowViewTintColor - LN_ADD_PROPERTY_GETTER(self, _sVTC, imp); + LN_ADD_PROPERTY_GETTER(self, shadowViewTintColor, imp); } } @@ -137,7 +132,7 @@ return super_class(&super, _cmd); \ return rv; }; - LN_ADD_PROPERTY_GETTER(_LNPopupUIBarAppearanceProxy.class, _bD, block); + LN_ADD_PROPERTY_GETTER(_LNPopupUIBarAppearanceProxy.class, _backgroundData, block); #pragma clang diagnostic pop } } diff --git a/LNPopupController/LNPopupController/Private/_LNWeakRef.h b/LNPopupController/LNPopupController/Private/_LNWeakRef.h index d38badc..de22258 100644 --- a/LNPopupController/LNPopupController/Private/_LNWeakRef.h +++ b/LNPopupController/LNPopupController/Private/_LNWeakRef.h @@ -2,8 +2,8 @@ // _LNWeakRef.h // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import diff --git a/LNPopupController/LNPopupController/Private/_LNWeakRef.m b/LNPopupController/LNPopupController/Private/_LNWeakRef.m index df49723..2edc3ed 100644 --- a/LNPopupController/LNPopupController/Private/_LNWeakRef.m +++ b/LNPopupController/LNPopupController/Private/_LNWeakRef.m @@ -2,8 +2,8 @@ // _LNWeakRef.m // LNPopupController // -// Created by Leo Natan on 7/25/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import "_LNWeakRef.h" diff --git a/LNPopupController/LNPopupController/UIViewController+LNPopupSupport.h b/LNPopupController/LNPopupController/UIViewController+LNPopupSupport.h index 0b7f7ec..8388242 100644 --- a/LNPopupController/LNPopupController/UIViewController+LNPopupSupport.h +++ b/LNPopupController/LNPopupController/UIViewController+LNPopupSupport.h @@ -2,8 +2,8 @@ // UIViewController+LNPopupSupport.h // LNPopupController // -// Created by Leo Natan on 7/24/15. -// Copyright © 2015-2021 Leo Natan. All rights reserved. +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. // #import @@ -11,16 +11,15 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @class UIViewController; -NS_REFINED_FOR_SWIFT /// The default popup snap percent. See `UIViewController.popupSnapPercent` for more information. -extern const double LNSnapPercentDefault; +extern const double LNSnapPercentDefault NS_REFINED_FOR_SWIFT; -NS_REFINED_FOR_SWIFT /// Available interaction styles with the popup bar and popup content view. typedef NS_ENUM(NSInteger, LNPopupInteractionStyle) { /// The default interaction style for the current environment. @@ -37,7 +36,7 @@ typedef NS_ENUM(NSInteger, LNPopupInteractionStyle) { /// No interaction LNPopupInteractionStyleNone = 0xFFFF -} NS_SWIFT_NAME(UIViewController.__PopupInteractionStyle); +} NS_REFINED_FOR_SWIFT NS_SWIFT_NAME(UIViewController.__PopupInteractionStyle); /// The state of the popup presentation. typedef NS_ENUM(NSInteger, LNPopupPresentationState){ @@ -52,43 +51,10 @@ typedef NS_ENUM(NSInteger, LNPopupPresentationState){ LNPopupPresentationStateHidden LN_DEPRECATED_API("Use LNPopupPresentationStateBarHidden instead.") = LNPopupPresentationStateBarHidden, LNPopupPresentationStateClosed LN_DEPRECATED_API("Use LNPopupPresentationStateBarPresented instead.") = LNPopupPresentationStateBarPresented, - LNPopupPresentationStateTransitioning NS_SWIFT_UNAVAILABLE("Should no longer be used.") LN_DEPRECATED_API("Should no longer be used.") = 2, + LNPopupPresentationStateTransitioning LN_UNAVAILABLE_API("Should no longer be used.") = 2, } NS_SWIFT_NAME(UIViewController.PopupPresentationState); -/// Popup content support for ``UIViewController`` subclasses. -@interface UIViewController (LNPopupContent) - -/// The popup item used to represent the view controller in a popup presentation. (read-only) -/// -/// This is a unique instance of ``LNPopupItem``, created to represent the view controller when it is presented in a popup. The ``LNPopupItem`` object is created the first time the property is accessed. Therefore, you should not access this property if you are not using popup presentation to display the view controller. To ensure the popup item is configured, you can either override this property and add code to create the bar button items when first accessed or create the items in your view controller's initialization code. -/// -/// The default behavior is to create a popup item that displays the view controller's title. -@property (nonatomic, retain, readonly) LNPopupItem* popupItem; - -/// Return the view to which the popup interaction gesture recognizer should be added to. -/// -/// The default implementation returns the controller's view. @see `UIViewController.popupContentView` -@property (nonatomic, strong, readonly) __kindof UIView* viewForPopupInteractionGestureRecognizer; - -/// Gives the popup content controller the opportunity to place the popup close button within its own view hierarchy, instead of the system-defined placement. -/// -/// The default implementation of this method does nothing and returns `false`. -/// -/// - Returns: Return `true` if the popup close button has been positioned in the controller's view hierarchy, or `false` to allow the system to handle positioning of the button. -- (BOOL)positionPopupCloseButton:(LNPopupCloseButton*)popupCloseButton; - -/// Called to notify the view controller that its view is about to be added to the container controller's popup content view. -/// -/// - Parameter popupContentView: The popup content view, or `nil`. -- (void)viewWillMoveToPopupContainerContentView:(nullable LNPopupContentView*)popupContentView NS_REQUIRES_SUPER; - -/// Called to notify the view controller that its view has just been added to the container controller's popup content view. -/// -/// - Parameter popupContentView: The popup content view, or `nil`. -- (void)viewDidMoveToPopupContainerContentView:(nullable LNPopupContentView*)popupContentView NS_REQUIRES_SUPER; - -@end - +NS_SWIFT_UI_ACTOR /// A set of methods, used to respond to popup presentation changes. @protocol LNPopupPresentationDelegate @@ -146,7 +112,7 @@ typedef NS_ENUM(NSInteger, LNPopupPresentationState){ /// - controller: The controller for popup presentation. /// - animated: Pass `true` to animate the presentation; otherwise, pass `false`. /// - completion: The block to execute after the presentation finishes. This block has no return value and takes no parameters. You may specify `nil` for this parameter. -- (void)presentPopupBarWithContentViewController:(UIViewController*)controller animated:(BOOL)animated completion:(nullable void(^)(void))completion NS_SWIFT_DISABLE_ASYNC; +- (void)presentPopupBarWithContentViewController:(UIViewController*)controller animated:(BOOL)animated completion:(nullable void(^)(void))completion NS_REFINED_FOR_SWIFT NS_SWIFT_DISABLE_ASYNC; /// Presents an interactive popup bar in the receiver's view hierarchy and optionally opens the popup in the same animation. The popup bar is attached to the receiver's docking view. @@ -159,30 +125,34 @@ typedef NS_ENUM(NSInteger, LNPopupPresentationState){ /// - openPopup: Pass `true` to open the popup in the same animation; otherwise, pass `false`. /// - animated: Pass `true` to animate the presentation; otherwise, pass `false`. /// - completion: The block to execute after the presentation finishes. This block has no return value and takes no parameters. You may specify `nil` for this parameter. -- (void)presentPopupBarWithContentViewController:(UIViewController*)controller openPopup:(BOOL)openPopup animated:(BOOL)animated completion:(nullable void(^)(void))completion NS_SWIFT_DISABLE_ASYNC; +- (void)presentPopupBarWithContentViewController:(UIViewController*)controller openPopup:(BOOL)openPopup animated:(BOOL)animated completion:(nullable void(^)(void))completion NS_REFINED_FOR_SWIFT NS_SWIFT_DISABLE_ASYNC; /// Opens the popup, displaying the content view controller's view. /// - Parameters: /// - animated: Pass `true` to animate; otherwise, pass `false`. /// - completion: The block to execute after the popup is opened. This block has no return value and takes no parameters. You may specify `nil` for this parameter. -- (void)openPopupAnimated:(BOOL)animated completion:(nullable void(^)(void))completion NS_SWIFT_DISABLE_ASYNC; +- (void)openPopupAnimated:(BOOL)animated completion:(nullable void(^)(void))completion NS_REFINED_FOR_SWIFT NS_SWIFT_DISABLE_ASYNC; /// Closes the popup, hiding the content view controller's view. /// - Parameters: /// - animated: Pass `true` to animate; otherwise, pass `false`. /// - completion: The block to execute after the popup is closed. This block has no return value and takes no parameters. You may specify `nil` for this parameter. -- (void)closePopupAnimated:(BOOL)animated completion:(nullable void(^)(void))completion NS_SWIFT_DISABLE_ASYNC; +- (void)closePopupAnimated:(BOOL)animated completion:(nullable void(^)(void))completion NS_REFINED_FOR_SWIFT NS_SWIFT_DISABLE_ASYNC; /// Dismisses the popup presentation, closing the popup if open and dismissing the popup bar. /// - Parameters: /// - animated: Pass `true` to animate; otherwise, pass `false`. /// - completion: The block to execute after the dismissal. This block has no return value and takes no parameters. You may specify `nil` for this parameter. -- (void)dismissPopupBarAnimated:(BOOL)animated completion:(nullable void(^)(void))completion NS_SWIFT_DISABLE_ASYNC; +- (void)dismissPopupBarAnimated:(BOOL)animated completion:(nullable void(^)(void))completion NS_REFINED_FOR_SWIFT NS_SWIFT_DISABLE_ASYNC; - -/// The popup bar interaction style. +/// The popup interaction style. @property (nonatomic, assign) LNPopupInteractionStyle popupInteractionStyle NS_REFINED_FOR_SWIFT; +/// The effective popup interaction style. (read-only) +/// +/// Use this property's value to determine, at runtime, what the result of `LNPopupInteractionStyleDefault` is. +@property (nonatomic, assign, readonly) LNPopupInteractionStyle effectivePopupInteractionStyle NS_REFINED_FOR_SWIFT; + /// The percent of the container controller's view height to drag before closing the popup. @property (nonatomic, assign) double popupSnapPercent NS_REFINED_FOR_SWIFT; @@ -217,12 +187,9 @@ typedef NS_ENUM(NSInteger, LNPopupPresentationState){ /// The delegate that handles popup presentation-related messages. @property (nonatomic, weak) id popupPresentationDelegate; -/// The content view controller of the receiver. If there is no popover presentation, the property will be @c nil. (read-only) +/// The content view controller of the receiver. If there is no popup presentation, the property will be @c nil. (read-only) @property (nullable, nonatomic, strong, readonly) __kindof UIViewController* popupContentViewController; -/// The popup presentation container view controller of the receiver. If the receiver is not part of a popover presentation, the property will be @c nil. (read-only) -@property (nullable, nonatomic, weak, readonly) __kindof UIViewController* popupPresentationContainerViewController; - /// Controls whether interaction with the popup generates haptic feedback to the user. /// /// Defaults to @c true. @@ -259,16 +226,76 @@ typedef NS_ENUM(NSInteger, LNPopupPresentationState){ @end -@interface UIViewController (Deprecations) - -/// @warning This API is no longer supported. Use @c bottomDockingViewForPopupBar instead. -@property (nullable, nonatomic, strong, readonly) __kindof UIView* bottomDockingViewForPopup LN_UNAVAILABLE_API("Use bottomDockingViewForPopupBar instead."); - -/// Call this method to update the popup bar appearance (style, tint color, etc.) according to its docking view. You should call this after updating the docking view. +NS_SWIFT_UI_ACTOR +/// Protocol that enables optimized popup transitions. /// -/// If the popup bar's @c inheritsAppearanceFromDockingView property is set to @c false, or a custom popup bar view controller is used, this method has no effect. See @c LNPopupBar.inheritsAppearanceFromDockingView and @c LNPopupBar.customBarViewController for more information. -- (void)updatePopupBarAppearance LN_UNAVAILABLE_API("Use setNeedsPopupBarAppearanceUpdate instead."); +/// Conform your custom view to this protocol and implement its properties, and the system will smoothly transition from and to the popup image view by applying values to the appropriate properties. +@protocol LNPopupTransitionView +/// The corner radius of the view. +@property (nonatomic, assign) CGFloat cornerRadius; +/// The shadow displayed underneath the view. +@property (nonatomic, copy, nullable) NSShadow* shadow; + +@optional +/// Implement this property to return `false` if your custom transition view does not support shadows. +@property (nonatomic, assign, readonly) BOOL supportsShadow; @end +/// Popup content support for ``UIViewController`` subclasses. +@interface UIViewController (LNPopupContent) + +/// The popup item used to represent the view controller in a popup presentation. (read-only) +/// +/// This is a unique instance of ``LNPopupItem``, created to represent the view controller when it is presented in a popup. The ``LNPopupItem`` object is created the first time the property is accessed. Therefore, you should not access this property if you are not using popup presentation to display the view controller. To ensure the popup item is configured, you can either override this property and add code to create the bar button items when first accessed or create the items in your view controller's initialization code. +/// +/// The default behavior is to create a popup item that displays the view controller's title. +@property (nonatomic, retain, readonly) LNPopupItem* popupItem; + +/// Return the view to which the popup interaction gesture recognizer should be added to. +/// +/// The default implementation returns the controller's view. @see `UIViewController.popupContentView` +@property (nonatomic, strong, readonly) __kindof UIView* viewForPopupInteractionGestureRecognizer; + +/// The popup presentation container view controller of the receiver. If the receiver is not part of a popup presentation, the property will be @c nil. (read-only) +@property (nullable, nonatomic, weak, readonly) __kindof UIViewController* popupPresentationContainerViewController; + +/// Gives the popup content controller the opportunity to place the popup close button within its own view hierarchy, instead of the system-defined placement. +/// +/// The default implementation of this method does nothing and returns `false`. +/// +/// - Returns: Return `true` if the popup close button has been positioned in the controller's view hierarchy, or `false` to allow the system to handle positioning of the button. +- (BOOL)positionPopupCloseButton:(LNPopupCloseButton*)popupCloseButton; + +/// Asks the popup content controller to provide a view for transitioning from `fromState` to `toState`. For no transition, return `nil`. If a valid view is provided, the system will transition between the view and popup bar image view. +/// +/// For optimal results, return a `LNPopupImageView` instance that displays the same image displayed in the popup bar's image view. The system automatically will smoothly transition between the popup bar's image view and the `LNPopupImageView` instance, taking into account the corner radii and shadows of the views. +/// +/// By default, the system discovers `LNPopupImageView` image views in your popup content and automatically transition to them. **There must only be a single visible `LNPopupImageView` image view in the popup content controller's view hierarchy, or the results will be undefined.** To enable the automatic discovery, either do not implement this method, or call the super implementation to return the discovered `LNPopupImageView` instance. +/// +/// You can also return a custom view from the popup content controller's view hierarchy. The system will attempt to match the attributes of the provided view and the popup bar's image view as closely as possible to transition smoothly between them. Implement the `LNPopupTransitionView` protocol in your custom view to allow the system to smoothly transition between your custom view and the popup bar image view. +/// +/// **The returned view must be part of the content controller's view hierarchy** or it will be ignored by the system and no transition will take place. +/// +/// The default implementation of this method returns an instance of `LNPopupImageView`, if in the popup content view hierarchy, or `nil` and no transition is performed. If more than one instance of `LNPopupImageView` exist, which one is returned automatically is undefined behavior, and you should implemented the method and return the correct instance. +/// +/// - Note: Transitions are only available for prominent and floating popup bar styles with drag interaction style. Any other combination will result in no transition and this method will not be called by the system. +/// +/// - Returns: Return `nil` for no transition or a valid view to transition to and/or from. +- (nullable UIView*)viewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState NS_SWIFT_NAME(viewForPopupTransition(from:to:)); + +/// Called to notify the view controller that its view is about to be added to the container controller's popup content view. +/// +/// - Parameter popupContentView: The popup content view, or `nil`. +- (void)viewWillMoveToPopupContainerContentView:(nullable LNPopupContentView*)popupContentView NS_REQUIRES_SUPER; + +/// Called to notify the view controller that its view has just been added to the container controller's popup content view. +/// +/// - Parameter popupContentView: The popup content view, or `nil`. +- (void)viewDidMoveToPopupContainerContentView:(nullable LNPopupContentView*)popupContentView NS_REQUIRES_SUPER; + +@end + +@interface LNPopupImageView (TransitionSupport) @end + NS_ASSUME_NONNULL_END diff --git a/LNPopupController/include/LNPopupController/LNPopupImageView.h b/LNPopupController/include/LNPopupController/LNPopupImageView.h new file mode 120000 index 0000000..926ee3a --- /dev/null +++ b/LNPopupController/include/LNPopupController/LNPopupImageView.h @@ -0,0 +1 @@ +../../LNPopupController/LNPopupImageView.h \ No newline at end of file diff --git a/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/project.pbxproj b/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/project.pbxproj index 3104475..4583288 100644 --- a/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/project.pbxproj +++ b/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/project.pbxproj @@ -3,41 +3,86 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ - 3908C34C1E7C9EA200451B5D /* SettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3908C34B1E7C9EA200451B5D /* SettingsTableViewController.m */; }; - 39140B901DBD69540036A6C5 /* Music.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 397C560D1B74DA66007A67F0 /* Music.storyboard */; }; + 3901289526CFC1D60002612D /* LNPopupControllerExampleSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 3901289426CFC1D60002612D /* LNPopupControllerExampleSupport.m */; }; 39277A091B58228000293F95 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 39277A081B58228000293F95 /* main.m */; }; 39277A0C1B58228000293F95 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 39277A0B1B58228000293F95 /* AppDelegate.m */; }; 39277A151B58228000293F95 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39277A131B58228000293F95 /* Main.storyboard */; }; 39277A171B58228000293F95 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39277A161B58228000293F95 /* Assets.xcassets */; }; - 393F23231E16BF1D000E969D /* MapScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 393F23221E16BF1D000E969D /* MapScene.storyboard */; }; + 392E2AC52AD5CAB600944CB2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 392E2AC42AD5CAB600944CB2 /* LaunchScreen.storyboard */; }; 393F23251E16C04A000E969D /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23241E16C04A000E969D /* MapViewController.swift */; }; 393F23271E16C192000E969D /* CustomMapBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23261E16C192000E969D /* CustomMapBarViewController.swift */; }; 393F23291E16CF90000E969D /* LocationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23281E16CF90000E969D /* LocationsController.swift */; }; - 393F232B1E16D1E4000E969D /* HigherSearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F232A1E16D1E4000E969D /* HigherSearchBar.swift */; }; - 394198482B4EFCA300FBC92D /* TOInsetGroupedTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 394198472B4EFCA300FBC92D /* TOInsetGroupedTableView.m */; }; - 3941984C2B4EFD6D00FBC92D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3941984B2B4EFD6D00FBC92D /* LaunchScreen.storyboard */; }; + 394E1AA7276C014900C5BE31 /* LNPopupDemoContextMenuInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 394E1AA6276C014900C5BE31 /* LNPopupDemoContextMenuInteraction.m */; }; + 394E1AA8276C0D9300C5BE31 /* LNPopupControllerExampleSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 3901289426CFC1D60002612D /* LNPopupControllerExampleSupport.m */; }; + 394E1AA9276C0DA600C5BE31 /* DemoGallery.m in Sources */ = {isa = PBXBuildFile; fileRef = 39756326254ED9EB0066981E /* DemoGallery.m */; }; 39631FAD230DA03E0059D119 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 39631FAC230DA03E0059D119 /* SceneDelegate.m */; }; 39756327254ED9EB0066981E /* DemoGallery.m in Sources */ = {isa = PBXBuildFile; fileRef = 39756326254ED9EB0066981E /* DemoGallery.m */; }; 397C56281B7538A5007A67F0 /* DemoAlbumTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C56271B7538A5007A67F0 /* DemoAlbumTableViewController.swift */; }; 397C562A1B753A45007A67F0 /* MusicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C56291B753A45007A67F0 /* MusicCell.swift */; }; + 3980E7FC26DEBCAF00AC0728 /* LoremIpsum in Frameworks */ = {isa = PBXBuildFile; productRef = 3980E7FB26DEBCAF00AC0728 /* LoremIpsum */; }; 39837A201B756F1A004D2DA9 /* RandomColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 39837A1F1B756F1A004D2DA9 /* RandomColors.m */; }; 39837A241B758541004D2DA9 /* DemoMusicPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39837A231B758541004D2DA9 /* DemoMusicPlayerController.swift */; }; 39837A261B759721004D2DA9 /* PortraitTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39837A251B759721004D2DA9 /* PortraitTabBarController.swift */; }; 3985DE602549539B00CD76EE /* IntroWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3985DE5F2549539B00CD76EE /* IntroWebViewController.m */; }; - 3988E3581B59C3000039C09B /* FirstViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3988E3571B59C3000039C09B /* FirstViewController.m */; }; + 3988E3581B59C3000039C09B /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3988E3571B59C3000039C09B /* DemoViewController.m */; }; 399748721D5652250079492B /* DemoPopupContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 399748711D5652250079492B /* DemoPopupContentViewController.m */; }; - 39A3B58B230D400B00E10425 /* SplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39A3B58A230D400B00E10425 /* SplitViewController.m */; }; + 39988C762AA1557F00C3BB04 /* SafeSystemImages.m in Sources */ = {isa = PBXBuildFile; fileRef = 39988C752AA1557F00C3BB04 /* SafeSystemImages.m */; }; + 39988C772AA1557F00C3BB04 /* SafeSystemImages.m in Sources */ = {isa = PBXBuildFile; fileRef = 39988C752AA1557F00C3BB04 /* SafeSystemImages.m */; }; + 39A3B58B230D400B00E10425 /* LNSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39A3B58A230D400B00E10425 /* LNSplitViewController.m */; }; + 39B0DFE62B1819A9008CCF36 /* MapScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFE92B1819A9008CCF36 /* MapScene.storyboard */; }; + 39B0DFE72B1819A9008CCF36 /* MapScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFE92B1819A9008CCF36 /* MapScene.storyboard */; }; + 39B0DFEA2B1819BC008CCF36 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFED2B1819BC008CCF36 /* Settings.storyboard */; }; + 39B0DFEB2B1819BC008CCF36 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFED2B1819BC008CCF36 /* Settings.storyboard */; }; + 39B0DFEE2B1819C2008CCF36 /* ManualLayoutScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFF12B1819C2008CCF36 /* ManualLayoutScene.storyboard */; }; + 39B0DFEF2B1819C2008CCF36 /* ManualLayoutScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFF12B1819C2008CCF36 /* ManualLayoutScene.storyboard */; }; + 39B0DFF22B1819EF008CCF36 /* Music.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFF52B1819EF008CCF36 /* Music.storyboard */; }; + 39B0DFF32B1819EF008CCF36 /* Music.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39B0DFF52B1819EF008CCF36 /* Music.storyboard */; }; + 39B645EA2CA5A97B00AB038B /* ScrollingColorsPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B645E92CA5A97B00AB038B /* ScrollingColorsPageViewController.swift */; }; + 39B645EB2CA5A97B00AB038B /* ScrollingColorsPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B645E92CA5A97B00AB038B /* ScrollingColorsPageViewController.swift */; }; + 39B645ED2CA5AA1300AB038B /* PageCardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B645EC2CA5AA1300AB038B /* PageCardViewController.swift */; }; + 39B645EE2CA5AA1300AB038B /* PageCardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B645EC2CA5AA1300AB038B /* PageCardViewController.swift */; }; + 39B645F02CA61B0200AB038B /* ScrollingMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B645EF2CA61B0200AB038B /* ScrollingMapViewController.swift */; }; + 39B645F12CA61B0200AB038B /* ScrollingMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39B645EF2CA61B0200AB038B /* ScrollingMapViewController.swift */; }; 39BBA86924FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BBA86824FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift */; }; - 39BBA86A24FEC3E500D9712A /* ManualLayoutScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39BBA86524FEC25400D9712A /* ManualLayoutScene.storyboard */; }; - 39DA0E8322D7B9C6001E63A0 /* NSObject+XcodeBugs.m in Sources */ = {isa = PBXBuildFile; fileRef = 39DA0E8222D7B9C6001E63A0 /* NSObject+XcodeBugs.m */; }; + 39BBA86C24FEC3E800D9712A /* ManualLayoutCustomBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BBA86824FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift */; }; + 39BF83D32B554AE800917649 /* LNPreviewToContextMenu in Frameworks */ = {isa = PBXBuildFile; productRef = 39BF83D22B554AE800917649 /* LNPreviewToContextMenu */; }; + 39BF83D42B554AE800917649 /* LNPreviewToContextMenu in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 39BF83D22B554AE800917649 /* LNPreviewToContextMenu */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 39BF83D62B554AF400917649 /* LNPreviewToContextMenu in Frameworks */ = {isa = PBXBuildFile; productRef = 39BF83D52B554AF400917649 /* LNPreviewToContextMenu */; }; + 39BF83D72B554AF400917649 /* LNPreviewToContextMenu in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 39BF83D52B554AF400917649 /* LNPreviewToContextMenu */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 39C4026E2CA4ED9F00F1C743 /* ScrollingColorsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39C4026D2CA4ED9F00F1C743 /* ScrollingColorsViewController.swift */; }; + 39D6C8B32B2D01E600F53E70 /* LNTouchVisualizer in Frameworks */ = {isa = PBXBuildFile; productRef = 39D6C8B22B2D01E600F53E70 /* LNTouchVisualizer */; }; + 39D6C8B42B2D01F600F53E70 /* LNTouchVisualizer in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 39D6C8B22B2D01E600F53E70 /* LNTouchVisualizer */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 39D6C8B62B2D020000F53E70 /* LNTouchVisualizer in Frameworks */ = {isa = PBXBuildFile; productRef = 39D6C8B52B2D020000F53E70 /* LNTouchVisualizer */; }; + 39D6C8B72B2D020000F53E70 /* LNTouchVisualizer in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 39D6C8B52B2D020000F53E70 /* LNTouchVisualizer */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 39D6C8BB2B2D02B500F53E70 /* SettingKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 39D6C8B92B2D02B500F53E70 /* SettingKeys.m */; }; + 39D6C8BC2B2D02B500F53E70 /* SettingKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 39D6C8B92B2D02B500F53E70 /* SettingKeys.m */; }; + 39D6C8BD2B2D02B500F53E70 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D6C8BA2B2D02B500F53E70 /* SettingsViewController.swift */; }; + 39D6C8BE2B2D02B500F53E70 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39D6C8BA2B2D02B500F53E70 /* SettingsViewController.swift */; }; 39DB61801B8891ED001BFF8F /* LNPopupController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39DB52F51B5823490061C589 /* LNPopupController.framework */; }; 39DB61811B8891ED001BFF8F /* LNPopupController.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 39DB52F51B5823490061C589 /* LNPopupController.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 39DDA0AE230D5F63007DCCD8 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39DDA0AD230D5F63007DCCD8 /* MapKit.framework */; }; - 39F8A07424DB3B1F0008B209 /* LoremIpsum in Frameworks */ = {isa = PBXBuildFile; productRef = 39F8A07324DB3B1F0008B209 /* LoremIpsum */; }; + 39FAFC3724E71A6C008BBC2D /* DemoAlbumTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C56271B7538A5007A67F0 /* DemoAlbumTableViewController.swift */; }; + 39FAFC3824E71A6C008BBC2D /* DemoMusicPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39837A231B758541004D2DA9 /* DemoMusicPlayerController.swift */; }; + 39FAFC3924E71A6C008BBC2D /* CustomMapBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23261E16C192000E969D /* CustomMapBarViewController.swift */; }; + 39FAFC3B24E71A6C008BBC2D /* LNSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39A3B58A230D400B00E10425 /* LNSplitViewController.m */; }; + 39FAFC3C24E71A6C008BBC2D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 39277A0B1B58228000293F95 /* AppDelegate.m */; }; + 39FAFC3E24E71A6C008BBC2D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 39277A081B58228000293F95 /* main.m */; }; + 39FAFC3F24E71A6C008BBC2D /* RandomColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 39837A1F1B756F1A004D2DA9 /* RandomColors.m */; }; + 39FAFC4024E71A6C008BBC2D /* LocationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23281E16CF90000E969D /* LocationsController.swift */; }; + 39FAFC4124E71A6C008BBC2D /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23241E16C04A000E969D /* MapViewController.swift */; }; + 39FAFC4224E71A6C008BBC2D /* DemoPopupContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 399748711D5652250079492B /* DemoPopupContentViewController.m */; }; + 39FAFC4324E71A6C008BBC2D /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3988E3571B59C3000039C09B /* DemoViewController.m */; }; + 39FAFC4424E71A6C008BBC2D /* PortraitTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39837A251B759721004D2DA9 /* PortraitTabBarController.swift */; }; + 39FAFC4524E71A6C008BBC2D /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 39631FAC230DA03E0059D119 /* SceneDelegate.m */; }; + 39FAFC4624E71A6C008BBC2D /* MusicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C56291B753A45007A67F0 /* MusicCell.swift */; }; + 39FAFC4824E71A6C008BBC2D /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39DDA0AD230D5F63007DCCD8 /* MapKit.framework */; }; + 39FAFC4B24E71A6C008BBC2D /* LoremIpsum in Frameworks */ = {isa = PBXBuildFile; productRef = 39FAFC3324E71A6C008BBC2D /* LoremIpsum */; }; + 39FAFC4F24E71A6C008BBC2D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39277A161B58228000293F95 /* Assets.xcassets */; }; + 39FAFC5024E71A6C008BBC2D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39277A131B58228000293F95 /* Main.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -64,37 +109,48 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 39D6C8B42B2D01F600F53E70 /* LNTouchVisualizer in Embed Frameworks */, + 39BF83D42B554AE800917649 /* LNPreviewToContextMenu in Embed Frameworks */, 39DB61811B8891ED001BFF8F /* LNPopupController.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + 39FAFC5124E71A6C008BBC2D /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 39D6C8B72B2D020000F53E70 /* LNTouchVisualizer in Embed Frameworks */, + 39BF83D72B554AF400917649 /* LNPreviewToContextMenu in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 3908C34A1E7C9EA200451B5D /* SettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewController.h; sourceTree = ""; }; - 3908C34B1E7C9EA200451B5D /* SettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewController.m; sourceTree = ""; }; + 3901289326CFC1D60002612D /* LNPopupControllerExampleSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupControllerExampleSupport.h; sourceTree = ""; }; + 3901289426CFC1D60002612D /* LNPopupControllerExampleSupport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LNPopupControllerExampleSupport.m; sourceTree = ""; }; 39277A041B58228000293F95 /* LNPopupControllerExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LNPopupControllerExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39277A081B58228000293F95 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 39277A0A1B58228000293F95 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39277A0B1B58228000293F95 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 39277A0D1B58228000293F95 /* FirstViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FirstViewController.h; sourceTree = ""; }; + 39277A0D1B58228000293F95 /* DemoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = ""; }; 39277A141B58228000293F95 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 39277A161B58228000293F95 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 39277A1B1B58228000293F95 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 393F23221E16BF1D000E969D /* MapScene.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MapScene.storyboard; sourceTree = ""; }; + 39277A1B1B58228000293F95 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Info.plist; sourceTree = ""; }; + 392E2AC42AD5CAB600944CB2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 393F23241E16C04A000E969D /* MapViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; 393F23261E16C192000E969D /* CustomMapBarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomMapBarViewController.swift; sourceTree = ""; }; 393F23281E16CF90000E969D /* LocationsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationsController.swift; sourceTree = ""; }; - 393F232A1E16D1E4000E969D /* HigherSearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HigherSearchBar.swift; sourceTree = ""; }; - 394198462B4EFCA300FBC92D /* TOInsetGroupedTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOInsetGroupedTableView.h; sourceTree = ""; }; - 394198472B4EFCA300FBC92D /* TOInsetGroupedTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOInsetGroupedTableView.m; sourceTree = ""; }; - 3941984B2B4EFD6D00FBC92D /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 394E1AA5276C014900C5BE31 /* LNPopupDemoContextMenuInteraction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNPopupDemoContextMenuInteraction.h; sourceTree = ""; }; + 394E1AA6276C014900C5BE31 /* LNPopupDemoContextMenuInteraction.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LNPopupDemoContextMenuInteraction.m; sourceTree = ""; }; 39631FAB230DA03D0059D119 /* SceneDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; 39631FAC230DA03E0059D119 /* SceneDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; 39756325254ED9EB0066981E /* DemoGallery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoGallery.h; sourceTree = ""; }; 39756326254ED9EB0066981E /* DemoGallery.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoGallery.m; sourceTree = ""; }; - 397C560D1B74DA66007A67F0 /* Music.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Music.storyboard; sourceTree = ""; }; 397C56271B7538A5007A67F0 /* DemoAlbumTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoAlbumTableViewController.swift; sourceTree = ""; }; 397C56291B753A45007A67F0 /* MusicCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MusicCell.swift; sourceTree = ""; }; 39837A1F1B756F1A004D2DA9 /* RandomColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RandomColors.m; sourceTree = ""; }; @@ -103,20 +159,31 @@ 39837A251B759721004D2DA9 /* PortraitTabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PortraitTabBarController.swift; sourceTree = ""; }; 3985DE5E2549539B00CD76EE /* IntroWebViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntroWebViewController.h; sourceTree = ""; }; 3985DE5F2549539B00CD76EE /* IntroWebViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntroWebViewController.m; sourceTree = ""; }; - 3988E3571B59C3000039C09B /* FirstViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirstViewController.m; sourceTree = ""; }; + 3988E3571B59C3000039C09B /* DemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoViewController.m; sourceTree = ""; tabWidth = 4; }; 399748701D5652250079492B /* DemoPopupContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoPopupContentViewController.h; sourceTree = ""; }; 399748711D5652250079492B /* DemoPopupContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoPopupContentViewController.m; sourceTree = ""; }; + 39988C742AA1557F00C3BB04 /* SafeSystemImages.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SafeSystemImages.h; sourceTree = ""; }; + 39988C752AA1557F00C3BB04 /* SafeSystemImages.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SafeSystemImages.m; sourceTree = ""; }; 39A134DA1B73FFC0003AB4C5 /* LNPopupControllerExample-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LNPopupControllerExample-Bridging-Header.h"; sourceTree = ""; }; - 39A3B589230D400B00E10425 /* SplitViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SplitViewController.h; sourceTree = ""; }; - 39A3B58A230D400B00E10425 /* SplitViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SplitViewController.m; sourceTree = ""; }; - 39A3B58C230D433100E10425 /* LNPopupControllerExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LNPopupControllerExample.entitlements; sourceTree = ""; }; - 39BBA86524FEC25400D9712A /* ManualLayoutScene.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ManualLayoutScene.storyboard; sourceTree = ""; }; + 39A3B589230D400B00E10425 /* LNSplitViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LNSplitViewController.h; sourceTree = ""; }; + 39A3B58A230D400B00E10425 /* LNSplitViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LNSplitViewController.m; sourceTree = ""; }; + 39B0DFE82B1819A9008CCF36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MapScene.storyboard; sourceTree = ""; }; + 39B0DFEC2B1819BC008CCF36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Settings.storyboard; sourceTree = ""; }; + 39B0DFF02B1819C2008CCF36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/ManualLayoutScene.storyboard; sourceTree = ""; }; + 39B0DFF42B1819EF008CCF36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Music.storyboard; sourceTree = ""; }; + 39B645E92CA5A97B00AB038B /* ScrollingColorsPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollingColorsPageViewController.swift; sourceTree = ""; }; + 39B645EC2CA5AA1300AB038B /* PageCardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageCardViewController.swift; sourceTree = ""; }; + 39B645EF2CA61B0200AB038B /* ScrollingMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollingMapViewController.swift; sourceTree = ""; }; 39BBA86824FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualLayoutCustomBarViewController.swift; sourceTree = ""; }; - 39DA0E8122D7B9C6001E63A0 /* NSObject+XcodeBugs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+XcodeBugs.h"; sourceTree = ""; }; - 39DA0E8222D7B9C6001E63A0 /* NSObject+XcodeBugs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+XcodeBugs.m"; sourceTree = ""; }; + 39C4026D2CA4ED9F00F1C743 /* ScrollingColorsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollingColorsViewController.swift; sourceTree = ""; }; + 39D6C8992B2CC3A100F53E70 /* LNPopupControllerExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LNPopupControllerExample.entitlements; sourceTree = ""; }; + 39D6C8B82B2D02B500F53E70 /* SettingKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SettingKeys.h; path = ../../../LNPopupSettings/SettingKeys.h; sourceTree = ""; }; + 39D6C8B92B2D02B500F53E70 /* SettingKeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SettingKeys.m; path = ../../../LNPopupSettings/SettingKeys.m; sourceTree = ""; }; + 39D6C8BA2B2D02B500F53E70 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingsViewController.swift; path = ../../../LNPopupSettings/SettingsViewController.swift; sourceTree = ""; }; 39DB52F01B5823480061C589 /* LNPopupController.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = LNPopupController.xcodeproj; path = ../LNPopupController/LNPopupController.xcodeproj; sourceTree = ""; }; 39DDA0AD230D5F63007DCCD8 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; - 39FAFC5824E71A6C008BBC2D /* LNPopupControllerExampleNoPopup-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "LNPopupControllerExampleNoPopup-Info.plist"; path = "/Users/lnatan/Desktop/GitHub (Private)/LNPopupController/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist"; sourceTree = ""; }; + 39FAFC5724E71A6C008BBC2D /* LNPopupControllerExampleNoPopup.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LNPopupControllerExampleNoPopup.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 39FAFC5824E71A6C008BBC2D /* LNPopupControllerExampleNoPopup-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "LNPopupControllerExampleNoPopup-Info.plist"; path = "../LNPopupControllerExampleNoPopup-Info.plist"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,9 +191,22 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 39BF83D32B554AE800917649 /* LNPreviewToContextMenu in Frameworks */, + 3980E7FC26DEBCAF00AC0728 /* LoremIpsum in Frameworks */, 39DDA0AE230D5F63007DCCD8 /* MapKit.framework in Frameworks */, 39DB61801B8891ED001BFF8F /* LNPopupController.framework in Frameworks */, - 39F8A07424DB3B1F0008B209 /* LoremIpsum in Frameworks */, + 39D6C8B32B2D01E600F53E70 /* LNTouchVisualizer in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 39FAFC4724E71A6C008BBC2D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 39D6C8B62B2D020000F53E70 /* LNTouchVisualizer in Frameworks */, + 39FAFC4824E71A6C008BBC2D /* MapKit.framework in Frameworks */, + 39FAFC4B24E71A6C008BBC2D /* LoremIpsum in Frameworks */, + 39BF83D62B554AF400917649 /* LNPreviewToContextMenu in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -136,10 +216,12 @@ 3908C3491E7C9E8A00451B5D /* Settings */ = { isa = PBXGroup; children = ( - 3908C34A1E7C9EA200451B5D /* SettingsTableViewController.h */, - 3908C34B1E7C9EA200451B5D /* SettingsTableViewController.m */, + 39B0DFED2B1819BC008CCF36 /* Settings.storyboard */, + 39D6C8B82B2D02B500F53E70 /* SettingKeys.h */, + 39D6C8B92B2D02B500F53E70 /* SettingKeys.m */, + 39D6C8BA2B2D02B500F53E70 /* SettingsViewController.swift */, ); - name = Settings; + path = Settings; sourceTree = ""; }; 392779FB1B58228000293F95 = { @@ -151,11 +233,13 @@ 39DDA0AC230D5F63007DCCD8 /* Frameworks */, ); sourceTree = ""; + tabWidth = 4; }; 39277A051B58228000293F95 /* Products */ = { isa = PBXGroup; children = ( 39277A041B58228000293F95 /* LNPopupControllerExample.app */, + 39FAFC5724E71A6C008BBC2D /* LNPopupControllerExampleNoPopup.app */, ); name = Products; sourceTree = ""; @@ -163,7 +247,7 @@ 39277A061B58228000293F95 /* LNPopupControllerExample */ = { isa = PBXGroup; children = ( - 39A3B58C230D433100E10425 /* LNPopupControllerExample.entitlements */, + 39D6C8992B2CC3A100F53E70 /* LNPopupControllerExample.entitlements */, 39277A131B58228000293F95 /* Main.storyboard */, 397C560B1B74D47D007A67F0 /* Demo - Testing Scene (Objective-C) */, 397C560C1B74D747007A67F0 /* Demo - Music Scene (Swift) */, @@ -179,11 +263,9 @@ 39277A071B58228000293F95 /* Supporting Files */ = { isa = PBXGroup; children = ( - 394198462B4EFCA300FBC92D /* TOInsetGroupedTableView.h */, - 394198472B4EFCA300FBC92D /* TOInsetGroupedTableView.m */, 397C560A1B74D45F007A67F0 /* Swift Bridging Header */, 39277A161B58228000293F95 /* Assets.xcassets */, - 3941984B2B4EFD6D00FBC92D /* LaunchScreen.storyboard */, + 392E2AC42AD5CAB600944CB2 /* LaunchScreen.storyboard */, 39277A1B1B58228000293F95 /* Info.plist */, 39FAFC5824E71A6C008BBC2D /* LNPopupControllerExampleNoPopup-Info.plist */, 39277A0A1B58228000293F95 /* AppDelegate.h */, @@ -193,18 +275,19 @@ 39277A081B58228000293F95 /* main.m */, ); name = "Supporting Files"; + path = Supporting; sourceTree = ""; }; 393F23211E16BEF5000E969D /* Demo - Custom Pupup Bar Scene (Swift) */ = { isa = PBXGroup; children = ( - 393F23221E16BF1D000E969D /* MapScene.storyboard */, + 39B0DFE92B1819A9008CCF36 /* MapScene.storyboard */, 393F23241E16C04A000E969D /* MapViewController.swift */, 393F23261E16C192000E969D /* CustomMapBarViewController.swift */, 393F23281E16CF90000E969D /* LocationsController.swift */, - 393F232A1E16D1E4000E969D /* HigherSearchBar.swift */, ); name = "Demo - Custom Pupup Bar Scene (Swift)"; + path = CustomBarScene; sourceTree = ""; }; 397C560A1B74D45F007A67F0 /* Swift Bridging Header */ = { @@ -220,48 +303,59 @@ children = ( 39756325254ED9EB0066981E /* DemoGallery.h */, 39756326254ED9EB0066981E /* DemoGallery.m */, - 39277A0D1B58228000293F95 /* FirstViewController.h */, - 3988E3571B59C3000039C09B /* FirstViewController.m */, + 39277A0D1B58228000293F95 /* DemoViewController.h */, + 3988E3571B59C3000039C09B /* DemoViewController.m */, 399748701D5652250079492B /* DemoPopupContentViewController.h */, 399748711D5652250079492B /* DemoPopupContentViewController.m */, - 39A3B589230D400B00E10425 /* SplitViewController.h */, - 39A3B58A230D400B00E10425 /* SplitViewController.m */, + 39A3B589230D400B00E10425 /* LNSplitViewController.h */, + 39A3B58A230D400B00E10425 /* LNSplitViewController.m */, 3985DE5E2549539B00CD76EE /* IntroWebViewController.h */, 3985DE5F2549539B00CD76EE /* IntroWebViewController.m */, + 3901289326CFC1D60002612D /* LNPopupControllerExampleSupport.h */, + 3901289426CFC1D60002612D /* LNPopupControllerExampleSupport.m */, + 394E1AA5276C014900C5BE31 /* LNPopupDemoContextMenuInteraction.h */, + 394E1AA6276C014900C5BE31 /* LNPopupDemoContextMenuInteraction.m */, + 39C4026D2CA4ED9F00F1C743 /* ScrollingColorsViewController.swift */, + 39B645EC2CA5AA1300AB038B /* PageCardViewController.swift */, + 39B645E92CA5A97B00AB038B /* ScrollingColorsPageViewController.swift */, + 39B645EF2CA61B0200AB038B /* ScrollingMapViewController.swift */, ); name = "Demo - Testing Scene (Objective-C)"; + path = TestingScene; sourceTree = ""; }; 397C560C1B74D747007A67F0 /* Demo - Music Scene (Swift) */ = { isa = PBXGroup; children = ( - 397C560D1B74DA66007A67F0 /* Music.storyboard */, + 39B0DFF52B1819EF008CCF36 /* Music.storyboard */, 397C56271B7538A5007A67F0 /* DemoAlbumTableViewController.swift */, 39837A231B758541004D2DA9 /* DemoMusicPlayerController.swift */, 397C56291B753A45007A67F0 /* MusicCell.swift */, 39837A251B759721004D2DA9 /* PortraitTabBarController.swift */, ); name = "Demo - Music Scene (Swift)"; + path = MusicScene; sourceTree = ""; }; 39837A221B756F9B004D2DA9 /* Utils */ = { isa = PBXGroup; children = ( - 39DA0E8122D7B9C6001E63A0 /* NSObject+XcodeBugs.h */, - 39DA0E8222D7B9C6001E63A0 /* NSObject+XcodeBugs.m */, 39837A211B756F4C004D2DA9 /* RandomColors.h */, 39837A1F1B756F1A004D2DA9 /* RandomColors.m */, + 39988C742AA1557F00C3BB04 /* SafeSystemImages.h */, + 39988C752AA1557F00C3BB04 /* SafeSystemImages.m */, ); - name = Utils; + path = Utils; sourceTree = ""; }; 39BBA86324FEC16600D9712A /* Demo - Custom Pupup Bar Scene - Manual Layout (Swift) */ = { isa = PBXGroup; children = ( - 39BBA86524FEC25400D9712A /* ManualLayoutScene.storyboard */, + 39B0DFF12B1819C2008CCF36 /* ManualLayoutScene.storyboard */, 39BBA86824FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift */, ); name = "Demo - Custom Pupup Bar Scene - Manual Layout (Swift)"; + path = CustomBarScene_ManualLayout; sourceTree = ""; }; 39DB52F11B5823480061C589 /* Products */ = { @@ -295,16 +389,44 @@ buildRules = ( ); dependencies = ( + 39114EDB26E2BF8B004FC75B /* PBXTargetDependency */, + 39114EDD26E2BF8B004FC75B /* PBXTargetDependency */, + 39114EDF26E2BF8B004FC75B /* PBXTargetDependency */, 39DB61831B8891EE001BFF8F /* PBXTargetDependency */, ); name = LNPopupControllerExample; packageProductDependencies = ( - 39F8A07324DB3B1F0008B209 /* LoremIpsum */, + 3980E7FB26DEBCAF00AC0728 /* LoremIpsum */, + 39D6C8B22B2D01E600F53E70 /* LNTouchVisualizer */, + 39BF83D22B554AE800917649 /* LNPreviewToContextMenu */, ); productName = LNPopupControllerExample; productReference = 39277A041B58228000293F95 /* LNPopupControllerExample.app */; productType = "com.apple.product-type.application"; }; + 39FAFC2E24E71A6C008BBC2D /* LNPopupControllerExampleNoPopup */ = { + isa = PBXNativeTarget; + buildConfigurationList = 39FAFC5424E71A6C008BBC2D /* Build configuration list for PBXNativeTarget "LNPopupControllerExampleNoPopup" */; + buildPhases = ( + 39FAFC3524E71A6C008BBC2D /* Sources */, + 39FAFC4724E71A6C008BBC2D /* Frameworks */, + 39FAFC4C24E71A6C008BBC2D /* Resources */, + 39FAFC5124E71A6C008BBC2D /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = LNPopupControllerExampleNoPopup; + packageProductDependencies = ( + 39FAFC3324E71A6C008BBC2D /* LoremIpsum */, + 39D6C8B52B2D020000F53E70 /* LNTouchVisualizer */, + 39BF83D52B554AF400917649 /* LNPreviewToContextMenu */, + ); + productName = LNPopupControllerExample; + productReference = 39FAFC5724E71A6C008BBC2D /* LNPopupControllerExampleNoPopup.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -313,7 +435,7 @@ attributes = { LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 9999; - ORGANIZATIONNAME = "Leo Natan"; + ORGANIZATIONNAME = "Léo Natan"; TargetAttributes = { 39277A031B58228000293F95 = { CreatedOnToolsVersion = 7.0; @@ -322,7 +444,7 @@ }; }; buildConfigurationList = 392779FF1B58228000293F95 /* Build configuration list for PBXProject "LNPopupControllerExample" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 15.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -331,7 +453,9 @@ ); mainGroup = 392779FB1B58228000293F95; packageReferences = ( - 39F8A07224DB3B1F0008B209 /* XCRemoteSwiftPackageReference "LoremIpsum" */, + 3980E7FA26DEBCAF00AC0728 /* XCRemoteSwiftPackageReference "LoremIpsum" */, + 39114ED726E2BF7A004FC75B /* XCRemoteSwiftPackageReference "LNPreviewToContextMenu" */, + 39D6C8B12B2D01E600F53E70 /* XCRemoteSwiftPackageReference "LNTouchVisualizer" */, ); productRefGroup = 39277A051B58228000293F95 /* Products */; projectDirPath = ""; @@ -344,6 +468,7 @@ projectRoot = ""; targets = ( 39277A031B58228000293F95 /* LNPopupControllerExample */, + 39FAFC2E24E71A6C008BBC2D /* LNPopupControllerExampleNoPopup */, ); }; /* End PBXProject section */ @@ -363,15 +488,29 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 39140B901DBD69540036A6C5 /* Music.storyboard in Resources */, - 39BBA86A24FEC3E500D9712A /* ManualLayoutScene.storyboard in Resources */, - 393F23231E16BF1D000E969D /* MapScene.storyboard in Resources */, - 3941984C2B4EFD6D00FBC92D /* LaunchScreen.storyboard in Resources */, + 39B0DFF22B1819EF008CCF36 /* Music.storyboard in Resources */, + 39B0DFEE2B1819C2008CCF36 /* ManualLayoutScene.storyboard in Resources */, + 39B0DFE62B1819A9008CCF36 /* MapScene.storyboard in Resources */, + 39B0DFEA2B1819BC008CCF36 /* Settings.storyboard in Resources */, + 392E2AC52AD5CAB600944CB2 /* LaunchScreen.storyboard in Resources */, 39277A171B58228000293F95 /* Assets.xcassets in Resources */, 39277A151B58228000293F95 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; + 39FAFC4C24E71A6C008BBC2D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 39B0DFF32B1819EF008CCF36 /* Music.storyboard in Resources */, + 39B0DFEF2B1819C2008CCF36 /* ManualLayoutScene.storyboard in Resources */, + 39B0DFE72B1819A9008CCF36 /* MapScene.storyboard in Resources */, + 39B0DFEB2B1819BC008CCF36 /* Settings.storyboard in Resources */, + 39FAFC4F24E71A6C008BBC2D /* Assets.xcassets in Resources */, + 39FAFC5024E71A6C008BBC2D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,33 +518,80 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3908C34C1E7C9EA200451B5D /* SettingsTableViewController.m in Sources */, 39BBA86924FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift in Sources */, 39756327254ED9EB0066981E /* DemoGallery.m in Sources */, 397C56281B7538A5007A67F0 /* DemoAlbumTableViewController.swift in Sources */, 39837A241B758541004D2DA9 /* DemoMusicPlayerController.swift in Sources */, + 39988C762AA1557F00C3BB04 /* SafeSystemImages.m in Sources */, 393F23271E16C192000E969D /* CustomMapBarViewController.swift in Sources */, - 393F232B1E16D1E4000E969D /* HigherSearchBar.swift in Sources */, - 39A3B58B230D400B00E10425 /* SplitViewController.m in Sources */, + 39A3B58B230D400B00E10425 /* LNSplitViewController.m in Sources */, 39277A0C1B58228000293F95 /* AppDelegate.m in Sources */, - 394198482B4EFCA300FBC92D /* TOInsetGroupedTableView.m in Sources */, - 39DA0E8322D7B9C6001E63A0 /* NSObject+XcodeBugs.m in Sources */, + 39B645F02CA61B0200AB038B /* ScrollingMapViewController.swift in Sources */, + 394E1AA7276C014900C5BE31 /* LNPopupDemoContextMenuInteraction.m in Sources */, 39277A091B58228000293F95 /* main.m in Sources */, + 39D6C8BB2B2D02B500F53E70 /* SettingKeys.m in Sources */, 39837A201B756F1A004D2DA9 /* RandomColors.m in Sources */, 393F23291E16CF90000E969D /* LocationsController.swift in Sources */, + 39B645EB2CA5A97B00AB038B /* ScrollingColorsPageViewController.swift in Sources */, + 39B645ED2CA5AA1300AB038B /* PageCardViewController.swift in Sources */, 3985DE602549539B00CD76EE /* IntroWebViewController.m in Sources */, 393F23251E16C04A000E969D /* MapViewController.swift in Sources */, + 39D6C8BD2B2D02B500F53E70 /* SettingsViewController.swift in Sources */, + 3901289526CFC1D60002612D /* LNPopupControllerExampleSupport.m in Sources */, 399748721D5652250079492B /* DemoPopupContentViewController.m in Sources */, - 3988E3581B59C3000039C09B /* FirstViewController.m in Sources */, + 3988E3581B59C3000039C09B /* DemoViewController.m in Sources */, + 39C4026E2CA4ED9F00F1C743 /* ScrollingColorsViewController.swift in Sources */, 39837A261B759721004D2DA9 /* PortraitTabBarController.swift in Sources */, 39631FAD230DA03E0059D119 /* SceneDelegate.m in Sources */, 397C562A1B753A45007A67F0 /* MusicCell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + 39FAFC3524E71A6C008BBC2D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 394E1AA8276C0D9300C5BE31 /* LNPopupControllerExampleSupport.m in Sources */, + 39B645EA2CA5A97B00AB038B /* ScrollingColorsPageViewController.swift in Sources */, + 394E1AA9276C0DA600C5BE31 /* DemoGallery.m in Sources */, + 39D6C8BE2B2D02B500F53E70 /* SettingsViewController.swift in Sources */, + 39BBA86C24FEC3E800D9712A /* ManualLayoutCustomBarViewController.swift in Sources */, + 39FAFC3724E71A6C008BBC2D /* DemoAlbumTableViewController.swift in Sources */, + 39FAFC3824E71A6C008BBC2D /* DemoMusicPlayerController.swift in Sources */, + 39FAFC3924E71A6C008BBC2D /* CustomMapBarViewController.swift in Sources */, + 39FAFC3B24E71A6C008BBC2D /* LNSplitViewController.m in Sources */, + 39FAFC3C24E71A6C008BBC2D /* AppDelegate.m in Sources */, + 39FAFC3E24E71A6C008BBC2D /* main.m in Sources */, + 39FAFC3F24E71A6C008BBC2D /* RandomColors.m in Sources */, + 39FAFC4024E71A6C008BBC2D /* LocationsController.swift in Sources */, + 39FAFC4124E71A6C008BBC2D /* MapViewController.swift in Sources */, + 39FAFC4224E71A6C008BBC2D /* DemoPopupContentViewController.m in Sources */, + 39FAFC4324E71A6C008BBC2D /* DemoViewController.m in Sources */, + 39D6C8BC2B2D02B500F53E70 /* SettingKeys.m in Sources */, + 39B645EE2CA5AA1300AB038B /* PageCardViewController.swift in Sources */, + 39FAFC4424E71A6C008BBC2D /* PortraitTabBarController.swift in Sources */, + 39B645F12CA61B0200AB038B /* ScrollingMapViewController.swift in Sources */, + 39988C772AA1557F00C3BB04 /* SafeSystemImages.m in Sources */, + 39FAFC4524E71A6C008BBC2D /* SceneDelegate.m in Sources */, + 39FAFC4624E71A6C008BBC2D /* MusicCell.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 39114EDB26E2BF8B004FC75B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 39114EDA26E2BF8B004FC75B /* LoremIpsum */; + }; + 39114EDD26E2BF8B004FC75B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 39114EDC26E2BF8B004FC75B /* LNTouchVisualizer */; + }; + 39114EDF26E2BF8B004FC75B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 39114EDE26E2BF8B004FC75B /* LNPreviewToContextMenu */; + }; 39DB61831B8891EE001BFF8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = LNPopupController; @@ -420,6 +606,39 @@ 39277A141B58228000293F95 /* Base */, ); name = Main.storyboard; + path = TestingScene; + sourceTree = ""; + }; + 39B0DFE92B1819A9008CCF36 /* MapScene.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 39B0DFE82B1819A9008CCF36 /* Base */, + ); + name = MapScene.storyboard; + sourceTree = ""; + }; + 39B0DFED2B1819BC008CCF36 /* Settings.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 39B0DFEC2B1819BC008CCF36 /* Base */, + ); + name = Settings.storyboard; + sourceTree = ""; + }; + 39B0DFF12B1819C2008CCF36 /* ManualLayoutScene.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 39B0DFF02B1819C2008CCF36 /* Base */, + ); + name = ManualLayoutScene.storyboard; + sourceTree = ""; + }; + 39B0DFF52B1819EF008CCF36 /* Music.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 39B0DFF42B1819EF008CCF36 /* Base */, + ); + name = Music.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ @@ -430,7 +649,6 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -459,7 +677,6 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; @@ -473,7 +690,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -486,7 +703,6 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -515,7 +731,6 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -523,7 +738,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; @@ -537,13 +752,13 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_ENTITLEMENTS = LNPopupControllerExample/LNPopupControllerExample.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = S9QFG2VH2E; GCC_PREPROCESSOR_DEFINITIONS = ( "LNPOPUP=1", @@ -551,17 +766,18 @@ "$(inherited)", ); INFOPLIST_FILE = LNPopupControllerExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); OTHER_SWIFT_FLAGS = "-DLNPOPUP"; - PRODUCT_BUNDLE_IDENTIFIER = "com.LeoNatan.LNPopupControllerExample-"; + PRODUCT_BUNDLE_IDENTIFIER = com.LeoNatan.LNPopupControllerExample; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_MACCATALYST = YES; - SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/Supporting/LNPopupControllerExample-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -572,28 +788,98 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_WEAK = YES; CODE_SIGN_ENTITLEMENTS = LNPopupControllerExample/LNPopupControllerExample.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; + CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = S9QFG2VH2E; GCC_PREPROCESSOR_DEFINITIONS = "LNPOPUP=1"; INFOPLIST_FILE = LNPopupControllerExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); OTHER_SWIFT_FLAGS = "-DLNPOPUP"; - PRODUCT_BUNDLE_IDENTIFIER = "com.LeoNatan.LNPopupControllerExample-"; + PRODUCT_BUNDLE_IDENTIFIER = com.LeoNatan.LNPopupControllerExample; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SUPPORTS_MACCATALYST = YES; SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/Supporting/LNPopupControllerExample-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 39FAFC5524E71A6C008BBC2D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; + DEVELOPMENT_TEAM = S9QFG2VH2E; + INFOPLIST_FILE = "LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.LeoNatan.LNPopupControllerExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SUPPORTS_MACCATALYST = YES; + SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/Supporting/LNPopupControllerExample-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 39FAFC5624E71A6C008BBC2D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; + DEVELOPMENT_TEAM = S9QFG2VH2E; + INFOPLIST_FILE = "LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.LeoNatan.LNPopupControllerExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SUPPORTS_MACCATALYST = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/Supporting/LNPopupControllerExample-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -621,10 +907,51 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 39FAFC5424E71A6C008BBC2D /* Build configuration list for PBXNativeTarget "LNPopupControllerExampleNoPopup" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 39FAFC5524E71A6C008BBC2D /* Debug */, + 39FAFC5624E71A6C008BBC2D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 39F8A07224DB3B1F0008B209 /* XCRemoteSwiftPackageReference "LoremIpsum" */ = { + 39114EC826E2B0D9004FC75B /* XCRemoteSwiftPackageReference "LNTouchVisualizer" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/LeoNatan/LNTouchVisualizer.git"; + requirement = { + branch = master; + kind = branch; + }; + }; + 39114ED726E2BF7A004FC75B /* XCRemoteSwiftPackageReference "LNPreviewToContextMenu" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/LeoNatan/LNPreviewToContextMenu.git"; + requirement = { + branch = master; + kind = branch; + }; + }; + 3980E7FA26DEBCAF00AC0728 /* XCRemoteSwiftPackageReference "LoremIpsum" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/LeoNatan/LoremIpsum"; + requirement = { + branch = master; + kind = branch; + }; + }; + 39D6C8B12B2D01E600F53E70 /* XCRemoteSwiftPackageReference "LNTouchVisualizer" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/LeoNatan/LNTouchVisualizer.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.3; + }; + }; + 39FAFC3424E71A6C008BBC2D /* XCRemoteSwiftPackageReference "LoremIpsum" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/lukaskubanek/LoremIpsum"; requirement = { @@ -635,9 +962,49 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 39F8A07324DB3B1F0008B209 /* LoremIpsum */ = { + 39114EDA26E2BF8B004FC75B /* LoremIpsum */ = { isa = XCSwiftPackageProductDependency; - package = 39F8A07224DB3B1F0008B209 /* XCRemoteSwiftPackageReference "LoremIpsum" */; + package = 3980E7FA26DEBCAF00AC0728 /* XCRemoteSwiftPackageReference "LoremIpsum" */; + productName = LoremIpsum; + }; + 39114EDC26E2BF8B004FC75B /* LNTouchVisualizer */ = { + isa = XCSwiftPackageProductDependency; + package = 39114EC826E2B0D9004FC75B /* XCRemoteSwiftPackageReference "LNTouchVisualizer" */; + productName = LNTouchVisualizer; + }; + 39114EDE26E2BF8B004FC75B /* LNPreviewToContextMenu */ = { + isa = XCSwiftPackageProductDependency; + package = 39114ED726E2BF7A004FC75B /* XCRemoteSwiftPackageReference "LNPreviewToContextMenu" */; + productName = LNPreviewToContextMenu; + }; + 3980E7FB26DEBCAF00AC0728 /* LoremIpsum */ = { + isa = XCSwiftPackageProductDependency; + package = 3980E7FA26DEBCAF00AC0728 /* XCRemoteSwiftPackageReference "LoremIpsum" */; + productName = LoremIpsum; + }; + 39BF83D22B554AE800917649 /* LNPreviewToContextMenu */ = { + isa = XCSwiftPackageProductDependency; + package = 39114ED726E2BF7A004FC75B /* XCRemoteSwiftPackageReference "LNPreviewToContextMenu" */; + productName = LNPreviewToContextMenu; + }; + 39BF83D52B554AF400917649 /* LNPreviewToContextMenu */ = { + isa = XCSwiftPackageProductDependency; + package = 39114ED726E2BF7A004FC75B /* XCRemoteSwiftPackageReference "LNPreviewToContextMenu" */; + productName = LNPreviewToContextMenu; + }; + 39D6C8B22B2D01E600F53E70 /* LNTouchVisualizer */ = { + isa = XCSwiftPackageProductDependency; + package = 39D6C8B12B2D01E600F53E70 /* XCRemoteSwiftPackageReference "LNTouchVisualizer" */; + productName = LNTouchVisualizer; + }; + 39D6C8B52B2D020000F53E70 /* LNTouchVisualizer */ = { + isa = XCSwiftPackageProductDependency; + package = 39D6C8B12B2D01E600F53E70 /* XCRemoteSwiftPackageReference "LNTouchVisualizer" */; + productName = LNTouchVisualizer; + }; + 39FAFC3324E71A6C008BBC2D /* LoremIpsum */ = { + isa = XCSwiftPackageProductDependency; + package = 39FAFC3424E71A6C008BBC2D /* XCRemoteSwiftPackageReference "LoremIpsum" */; productName = LoremIpsum; }; /* End XCSwiftPackageProductDependency section */ diff --git a/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExample.xcscheme b/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExample.xcscheme index 25b5229..ed06774 100644 --- a/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExample.xcscheme +++ b/LNPopupControllerExample/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExample.xcscheme @@ -1,10 +1,29 @@ + version = "1.7"> + + + + + + + + + + - - - - + isEnabled = "NO"> @@ -84,6 +94,13 @@ isEnabled = "YES"> + + + + + version = "2.0"> @@ -37,9 +37,11 @@ launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" - debugDocumentVersioning = "YES" + debugDocumentVersioning = "NO" + debugXPCServices = "NO" debugServiceExtension = "internal" - allowLocationSimulation = "YES"> + allowLocationSimulation = "YES" + queueDebuggingEnabled = "No"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/CustomMapBarViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/CustomMapBarViewController.swift new file mode 100644 index 0000000..df394bc --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/CustomMapBarViewController.swift @@ -0,0 +1,87 @@ +// +// CustomMapBarViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2016-12-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#if LNPOPUP +import UIKit + +class CustomMapBarView: UIView { + override var frame: CGRect { + didSet { + print("Size: \(self.frame)") + } + } +} + +class CustomMapBarViewController: LNPopupCustomBarViewController { + @IBOutlet weak var searchBar: UISearchBar! + @IBOutlet var heightConstraint: NSLayoutConstraint! + + override var wantsDefaultTapGestureRecognizer: Bool { + return false + } + + override var wantsDefaultHighlightGestureRecognizer: Bool { + return false + } + + fileprivate func updateConstraint() { + heightConstraint.constant = 65 + self.preferredContentSize = view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + } + + override func viewDidLoad() { + super.viewDidLoad() + + view.translatesAutoresizingMaskIntoConstraints = false + + updateConstraint() + + guard let bg = (containingPopupBar?.value(forKey: "backgroundView") as? UIView) else { + return + } + + bg.clipsToBounds = true + bg.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] + bg.layer.cornerRadius = 20 + bg.layer.cornerCurve = .continuous + + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + } + + override func viewIsAppearing(_ animated: Bool) { + super.viewIsAppearing(animated) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + } + + override func popupItemDidUpdate() { + searchBar.text = popupItem.title + } + + override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + coordinator.animate(alongsideTransition: { [unowned self] context in + updateConstraint() + }, completion: nil) + } +} +#endif diff --git a/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/LocationsController.swift b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/LocationsController.swift new file mode 100644 index 0000000..1d509d2 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/LocationsController.swift @@ -0,0 +1,46 @@ +// +// LocationsController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2016-12-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit + +class LocationsController: UITableViewController, UISearchBarDelegate { + @IBOutlet weak var searchBar: UISearchBar! + + override func viewDidLoad() { + super.viewDidLoad() + + searchBar.delegate = self + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + +#if LNPOPUP + searchBar.text = popupItem.title +#endif + } + + override func scrollViewDidScroll(_ scrollView: UIScrollView) { + searchBar.resignFirstResponder() + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + searchBar.resignFirstResponder() +#if LNPOPUP + popupItem.title = tableView.cellForRow(at: indexPath)?.textLabel?.text + popupPresentationContainer?.closePopup(animated: true, completion: nil) +#endif + } + + func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { +#if LNPOPUP + popupItem.title = searchText +#endif + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/MapViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/MapViewController.swift new file mode 100644 index 0000000..2ee272c --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene/MapViewController.swift @@ -0,0 +1,138 @@ +// +// MapViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2016-12-30. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#if LNPOPUP +import LNPopupController +#endif +import UIKit +import MapKit + +private extension UIImage { + class func gradientImage(withHeight height: CGFloat, scale: CGFloat, colors: [UIColor], locations: [CGFloat]) -> UIImage { + let renderer = UIGraphicsImageRenderer(size: CGSize(width: 1, height: height)) + let image = renderer.image { context in + let context = UIGraphicsGetCurrentContext()! + let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors.map { $0.cgColor } as CFArray, locations: locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: height), options: []) + } + + return image + } +} + +class MapViewController: UIViewController, UISearchBarDelegate { + @IBOutlet weak var mapView: MKMapView! + @IBOutlet weak var topVisualEffectView: UIVisualEffectView! + @IBOutlet weak var backButtonBackground: UIVisualEffectView! + private var popupContentVC: LocationsController! + + override func viewDidLoad() { + super.viewDidLoad() + + mapView.showsTraffic = false + mapView.pointOfInterestFilter = .includingAll + + backButtonBackground.layer.cornerRadius = 10.0 + backButtonBackground.layer.borderWidth = 1.0 + backButtonBackground.layer.borderColor = self.view.tintColor.cgColor + + backButtonBackground.effect = UIBlurEffect(style: .systemChromeMaterial) + backButtonBackground.layer.cornerCurve = .continuous + + if #available(iOS 17.0, *) { + topVisualEffectView.effect = UIBlurEffect(variableBlurRadius: 3.0, imageMask: UIImage(named: "statusBarMask")!) + } else { + topVisualEffectView.effect = UIBlurEffect(blurRadius: 10.0) + } + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + backButtonBackground.layer.borderColor = self.view.tintColor.cgColor + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + self.presentPopupBarIfNeeded(animated: false) + } + + func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool { +#if LNPOPUP + openPopup(animated: true, completion: nil) + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.popupContentVC.searchBar.becomeFirstResponder() + } +#endif + + return false; + } + + @IBAction private func presentButtonTapped(_ sender: Any) { + presentPopupBarIfNeeded(animated: true) + } + + private func presentPopupBarIfNeeded(animated: Bool) { +#if LNPOPUP + guard popupBar.customBarViewController == nil else { + return + } + + popupBar.standardAppearance.shadowColor = .clear + if let customMapBar = storyboard!.instantiateViewController(withIdentifier: "CustomMapBarViewController") as? CustomMapBarViewController { + popupBar.customBarViewController = customMapBar + + customMapBar.view.backgroundColor = .clear + customMapBar.searchBar.delegate = self + + if let searchTextField = customMapBar.searchBar.value(forKey: "searchField") as? UITextField, let clearButton = searchTextField.value(forKey: "_clearButton") as? UIButton { + clearButton.addTarget(self, action: #selector(self.clearButtonTapped), for: .primaryActionTriggered) + } + } else { + //Manual layout bar scene + shouldExtendPopupBarUnderSafeArea = false + popupBar.customBarViewController = ManualLayoutCustomBarViewController() + popupBar.standardAppearance.configureWithTransparentBackground() + } + + popupContentView.popupCloseButtonStyle = .none + popupContentView.backgroundEffect = UIBlurEffect(style: .systemChromeMaterial) +// popupContentView.isTranslucent = false + popupInteractionStyle = .customizedSnap(percent: 0.15) + + popupContentVC = (storyboard!.instantiateViewController(withIdentifier: "PopupContentController") as! LocationsController) + popupContentVC.tableView.backgroundColor = .clear + + presentPopupBar(with: self.popupContentVC, animated: animated, completion: nil) +#endif + } + + @objc private func clearButtonTapped(_ sender: Any) { +#if LNPOPUP + popupContentVC.popupItem.title = nil + popupContentVC.searchBar.text = nil +#endif + } + + @IBAction private func dismissButtonTapped(_ sender: Any) { +#if LNPOPUP + dismissPopupBar(animated: true) { + self.popupBar.customBarViewController = nil + } +#endif + } + +#if LNPOPUP + override var shouldFadePopupBarOnDismiss: Bool { + return true + } +#endif +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene_ManualLayout/Base.lproj/ManualLayoutScene.storyboard b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene_ManualLayout/Base.lproj/ManualLayoutScene.storyboard new file mode 100644 index 0000000..219e1ad --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene_ManualLayout/Base.lproj/ManualLayoutScene.storyboard @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene_ManualLayout/ManualLayoutCustomBarViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene_ManualLayout/ManualLayoutCustomBarViewController.swift new file mode 100644 index 0000000..87bc833 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/CustomBarScene_ManualLayout/ManualLayoutCustomBarViewController.swift @@ -0,0 +1,86 @@ +// +// ManualLayoutCustomBarViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2020-09-01. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#if LNPOPUP +@objc public +class ManualLayoutCustomBarViewController: LNPopupCustomBarViewController { + let centeredButton = UIButton(type: .system) + let leftButton = UIButton(type: .system) + let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial)) + + public +override func viewDidLoad() { + super.viewDidLoad() + + view.autoresizingMask = [] + + backgroundView.layer.masksToBounds = true + backgroundView.layer.cornerCurve = .continuous + backgroundView.layer.cornerRadius = 15 + view.addSubview(backgroundView) + + centeredButton.setTitle(NSLocalizedString("Centered", comment: ""), for: .normal) + centeredButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline) + centeredButton.sizeToFit() + view.addSubview(centeredButton) + + leftButton.setTitle("<- \(NSLocalizedString("Leading", comment: ""))", for: .normal) + leftButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline) + leftButton.sizeToFit() + view.addSubview(leftButton) + + self.preferredContentSize = CGSize(width: 0, height: 50) + animateSize() + } + + var idx = 0 + func animateSize() { + idx = 1 - idx; + UIView.animate(withDuration: 1.0, delay: 0.0, options: [.curveEaseInOut, .allowUserInteraction]) { + self.preferredContentSize = CGSize(width: 0, height: 50 + self.idx * 50) + } completion: { [weak self] _ in + guard let self else { + return + } + + self.animateSize() + } + } + + public +override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + let insetLeft = CGFloat.maximum(view.safeAreaInsets.left, 20) + let insetRight = CGFloat.maximum(view.safeAreaInsets.right, 20) + + backgroundView.frame = CGRect(x: insetLeft, y: 2, width: view.bounds.width - insetLeft - insetRight, height: view.bounds.height - 4) + centeredButton.center = backgroundView.center + if UIView.userInterfaceLayoutDirection(for: view.semanticContentAttribute) == .leftToRight { + leftButton.frame = CGRect(x: insetLeft + 20, y: backgroundView.center.y - leftButton.bounds.size.height / 2, width: leftButton.bounds.size.width, height: leftButton.bounds.size.height) + } else { + leftButton.frame = CGRect(x: view.bounds.width - insetRight - leftButton.bounds.width - 20, y: backgroundView.center.y - leftButton.bounds.size.height / 2, width: leftButton.bounds.size.width, height: leftButton.bounds.size.height) + } + } + + public +override var wantsDefaultTapGestureRecognizer: Bool { + return false + } + + public +override var wantsDefaultPanGestureRecognizer: Bool { + return false + } + + public +override var wantsDefaultHighlightGestureRecognizer: Bool { + return false + } +} +#endif diff --git a/LNPopupControllerExample/LNPopupControllerExample/Info.plist b/LNPopupControllerExample/LNPopupControllerExample/Info.plist index cd85e9f..47a3b55 100644 --- a/LNPopupControllerExample/LNPopupControllerExample/Info.plist +++ b/LNPopupControllerExample/LNPopupControllerExample/Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion en CFBundleDisplayName @@ -17,11 +19,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.10.38 + 3.0.6 CFBundleSignature ???? CFBundleVersion 1 + LSApplicationCategoryType + public.app-category.developer-tools LSRequiresIPhoneOS UIApplicationSceneManifest @@ -67,17 +71,16 @@ UISupportedInterfaceOrientations - UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationPortrait UISupportedInterfaceOrientations~ipad - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown diff --git a/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExample.entitlements b/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExample.entitlements index ee95ab7..5a034cd 100644 --- a/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExample.entitlements +++ b/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExample.entitlements @@ -2,9 +2,9 @@ - com.apple.security.app-sandbox - - com.apple.security.network.client - + com.apple.security.application-groups + + group.com.LeoNatan.LNPopupSettings + diff --git a/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist b/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist index cf8232c..21a6ca8 100644 --- a/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist +++ b/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist @@ -2,6 +2,8 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion en CFBundleDisplayName @@ -44,7 +46,7 @@ UILaunchStoryboardName - Main + LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities @@ -77,5 +79,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + LSApplicationCategoryType + public.app-category.developer-tools diff --git a/LNPopupControllerExample/LNPopupControllerExample/MusicScene/Base.lproj/Music.storyboard b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/Base.lproj/Music.storyboard new file mode 100644 index 0000000..568c139 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/Base.lproj/Music.storyboard @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/MusicScene/DemoAlbumTableViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/DemoAlbumTableViewController.swift new file mode 100644 index 0000000..f679a63 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/DemoAlbumTableViewController.swift @@ -0,0 +1,148 @@ +// +// DemoAlbumTableViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit +import SwiftUI +#if LNPOPUP +import LNPopupController +#endif +import LoremIpsum + +class DemoAlbumTableViewController: UITableViewController { + @IBOutlet var demoAlbumImageView: UIImageView! + + var images: [UIImage] + var titles: [String] + var subtitles: [String] + + required init?(coder aDecoder: NSCoder) { + images = [] + titles = [] + subtitles = [] + + super.init(coder:aDecoder) + } + + override func viewDidLoad() { + tabBarController?.view.tintColor = view.tintColor + + super.viewDidLoad() + +// let backgroundImageView = UIImageView(image: UIImage(named: "demoAlbum")) +// backgroundImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] +// backgroundImageView.contentMode = .scaleAspectFill +// let backgroundEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemThinMaterial)) +// backgroundEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] +// let container = UIView(frame: tableView.bounds) +// container.autoresizingMask = [.flexibleWidth, .flexibleHeight] +// backgroundImageView.frame = container.bounds +// backgroundEffectView.frame = container.bounds +// container.addSubview(backgroundImageView) +// container.addSubview(backgroundEffectView) +// +// tableView.backgroundView = container + + let view = ZStack { + Image("demoAlbum") + .resizable() + Color(uiColor: .secondarySystemBackground) + .opacity(0.35) + }.compositingGroup().blur(radius: 80, opaque: true) + + tableView.backgroundView = UIHostingController(rootView: view).view + + tableView.separatorEffect = UIVibrancyEffect(blurEffect: UIBlurEffect(style: .systemThinMaterial)) + +#if LNPOPUP + let barStyle = LNPopupBar.Style(rawValue: UserDefaults.settings.object(forKey: PopupSetting.barStyle) as? Int ?? 0)! + tabBarController?.popupBar.barStyle = barStyle + + if tabBarController?.popupBar.effectiveBarStyle == .floating { + let tba = UITabBarAppearance() + tba.backgroundEffect = UIBlurEffect(style: .systemThinMaterial) + tabBarController!.tabBar.standardAppearance = tba + + let nba = UINavigationBarAppearance() + nba.backgroundEffect = UIBlurEffect(style: .systemThinMaterial) + navigationController!.navigationBar.standardAppearance = nba + } +#endif + + demoAlbumImageView.layer.cornerCurve = .continuous + demoAlbumImageView.layer.cornerRadius = 8 + demoAlbumImageView.layer.masksToBounds = true + + for idx in 1...self.tableView(tableView, numberOfRowsInSection: 0) { + images += [UIImage(named: "genre\(idx)")!] + + var title = LoremIpsum.title + var sentence = LoremIpsum.sentence + +#if LNPOPUP + if UserDefaults.standard.bool(forKey: PopupSetting.forceRTL) { + title = title.applyingTransform(.latinToHebrew, reverse: false)! + sentence = sentence.applyingTransform(.latinToHebrew, reverse: false)! + } +#endif + + titles.append(title) + subtitles.append(sentence) + } + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 30 + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 2 + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let separator = UIView(frame: CGRect(x: view.layoutMargins.left, y: 0, width: tableView.bounds.size.width - view.layoutMargins.left, height: 1 / UIScreen.main.scale)) + separator.backgroundColor = .separator + separator.autoresizingMask = .flexibleWidth + let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: 2)) + view.addSubview(separator) + return view + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "MusicCell", for: indexPath) + + cell.imageView?.image = images[(indexPath as NSIndexPath).row] + cell.textLabel?.text = titles[(indexPath as NSIndexPath).row] + cell.detailTextLabel?.text = subtitles[(indexPath as NSIndexPath).row] + + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { +#if LNPOPUP + let popupContentController = DemoMusicPlayerController() + popupContentController.songTitle = titles[(indexPath as NSIndexPath).row] + popupContentController.albumTitle = subtitles[(indexPath as NSIndexPath).row] + popupContentController.albumArt = images[(indexPath as NSIndexPath).row] + + popupContentController.popupItem.accessibilityHint = NSLocalizedString("Double Tap to Expand the Mini Player", comment: "") + tabBarController?.popupContentView.popupCloseButton.accessibilityLabel = NSLocalizedString("Dismiss Now Playing Screen", comment: "") + + tabBarController?.presentPopupBar(with: popupContentController, animated: true, completion: nil) + tabBarController?.popupBar.imageView.layer.cornerRadius = 3 + tabBarController?.popupBar.tintColor = UIColor.label + tabBarController?.popupBar.progressViewStyle = .top + +#endif + + tableView.deselectRow(at: indexPath, animated: true) + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/MusicScene/DemoMusicPlayerController.swift b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/DemoMusicPlayerController.swift new file mode 100644 index 0000000..c8f6447 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/DemoMusicPlayerController.swift @@ -0,0 +1,375 @@ +// +// DemoMusicPlayerController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#if LNPOPUP +import UIKit +import SwiftUI +import LNPopupController + +fileprivate struct BackgroundView: UIViewRepresentable { + func makeUIView(context: Context) -> UIView { + let rv = UIView() + rv.tag = 666 + return rv + } + func updateUIView(_ uiView: UIView, context: Context) { + } +} + +fileprivate struct PopupTransitionImage: UIViewRepresentable { + let uiImage: UIImage + + func makeUIView(context: Context) -> LNPopupImageView { + let rv = LNPopupImageView() + rv.image = uiImage + rv.cornerRadius = 30.0 + + let shadow = NSShadow() + shadow.shadowOffset = .zero + shadow.shadowColor = UIColor.black.withAlphaComponent(0.5) + shadow.shadowBlurRadius = 10.0 + rv.shadow = shadow + + return rv + } + + func updateUIView(_ uiView: LNPopupImageView, context: Context) { + uiView.image = uiImage + } +} + +class PlaybackSettings: ObservableObject { + @Published var songTitle: String = "" + @Published var albumTitle: String = "" + @Published var albumArt: UIImage = UIImage() + + @Published var playbackProgress: Float = 0.0 + @Published var progressEditedByUser: Bool = false + @Published var volume: Float = 0.5 + @Published var isPlaying: Bool = true + + var onPlayPause: (() -> ())? = nil +} + +struct PlayerView: View { + @ObservedObject var playbackSettings = PlaybackSettings() + + var body: some View { + GeometryReader { geometry in + return VStack { + PopupTransitionImage(uiImage: playbackSettings.albumArt) + .aspectRatio(1.0, contentMode: .fit) + .padding([.leading, .trailing], 10) + .padding([.top], geometry.size.height * 60 / 896.0) + VStack(spacing: geometry.size.height * 30.0 / 896.0) { + HStack { + VStack(alignment: .leading) { + Text(playbackSettings.songTitle) + .font(.system(size: 20, weight: .bold)) + Text(playbackSettings.albumTitle) + .font(.system(size: 20, weight: .regular)) + } + .lineLimit(1) + .frame(minWidth: 0, + maxWidth: .infinity, + alignment: .topLeading) + Button(action: {}, label: { + Image(systemName: "ellipsis.circle") + .font(.title) + }) + } + Slider(value: $playbackSettings.playbackProgress, onEditingChanged: { editing in + playbackSettings.progressEditedByUser = editing + }) + .padding([.bottom], geometry.size.height * 30.0 / 896.0) + HStack { + Button(action: {}, label: { + Image(systemName: "backward.fill") + }) + .frame(minWidth: 0, maxWidth: .infinity) + Button(action: { + playbackSettings.isPlaying.toggle() + playbackSettings.onPlayPause?() + }, label: { + Image(systemName: playbackSettings.isPlaying ? "pause.fill" : "play.fill") + }) + .font(.system(size: 50, weight: .bold)) + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 50, maxHeight: 50) + Button(action: {}, label: { + Image(systemName: "forward.fill") + }) + .frame(minWidth: 0, maxWidth: .infinity) + } + .font(.system(size: 30, weight: .regular)) + .padding([.bottom], geometry.size.height * 20.0 / 896.0) + HStack { + Image(systemName: "speaker.fill") + Slider(value: $playbackSettings.volume) + Image(systemName: "speaker.wave.2.fill") + } + .font(.footnote) + .foregroundColor(.gray) + HStack { + Button(action: {}, label: { + Image(systemName: "shuffle") + }) + .frame(minWidth: 0, maxWidth: .infinity) + Button(action: {}, label: { + Image(systemName: "airplayaudio") + }) + .frame(minWidth: 0, maxWidth: .infinity) + Button(action: {}, label: { + Image(systemName: "repeat") + }) + .frame(minWidth: 0, maxWidth: .infinity) + } + .font(.body) + } + .padding(geometry.size.height * 40.0 / 896.0) + } + .frame(minWidth: 0, + maxWidth: .infinity, + minHeight: 0, + maxHeight: .infinity, + alignment: .top) + .background { + ZStack { + ZStack { + Image(uiImage: playbackSettings.albumArt) + .resizable() + Color(uiColor: .systemBackground) + .opacity(0.4) + }.compositingGroup().blur(radius: 90, opaque: true) + BackgroundView() + }.edgesIgnoringSafeArea(.all) + } + } + } +} + +class DemoMusicPlayerController: UIHostingController { + let accessibilityDateComponentsFormatter = DateComponentsFormatter() + var timer : Timer? + var popupCloseButton: LNPopupCloseButton? + + lazy var vibrancyView : UIVisualEffectView = { + let background = self.view.viewWithTag(666)! + let rv = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .systemMaterial), style: .separator)) + rv.translatesAutoresizingMaskIntoConstraints = false + background.addSubview(rv) + NSLayoutConstraint.activate([ + rv.leadingAnchor.constraint(equalTo: background.safeAreaLayoutGuide.leadingAnchor), + rv.trailingAnchor.constraint(equalTo: background.safeAreaLayoutGuide.trailingAnchor), + rv.topAnchor.constraint(equalTo: background.safeAreaLayoutGuide.topAnchor), + rv.bottomAnchor.constraint(equalTo: background.safeAreaLayoutGuide.bottomAnchor) + ]) + + return rv + }() + + let playerView = PlayerView() + + required init() { + super.init(rootView: playerView) + + playerView.playbackSettings.onPlayPause = { [weak self] in + guard let self else { + return + } + + self.updateBarItems(with: self.traitCollection) + } + + timer = Timer(timeInterval: 0.02, target: self, selector: #selector(DemoMusicPlayerController._timerTicked(_:)), userInfo: nil, repeats: true) + RunLoop.current.add(timer!, forMode: .common) + + accessibilityDateComponentsFormatter.unitsStyle = .spellOut + } + + fileprivate func updateBarItems(with traitCollection: UITraitCollection) { + let playPauseActionHandler: UIActionHandler = { [weak self] _ in + guard let self else { + return + } + self.playerView.playbackSettings.isPlaying.toggle() + self.updateBarItems(with: self.traitCollection) + } + + let scale: LNSystemImageScale + let backForwardScale: LNSystemImageScale + if LNPopupBar.Style(rawValue: UserDefaults.settings.object(forKey: .barStyle) as? Int ?? 0)! == LNPopupBar.Style.compact { + scale = .compact + backForwardScale = .compact + } else if UIDevice.current.userInterfaceIdiom == .pad && traitCollection.horizontalSizeClass == .regular { + scale = .larger + backForwardScale = .large + } else { + scale = .normal + backForwardScale = .normal + } + + let play = LNSystemBarButtonItem("play.fill", scale: scale != .larger ? .init(rawValue: scale.rawValue + 1)! : scale, primaryAction: UIAction(handler: playPauseActionHandler)) + play.accessibilityLabel = "Play" + play.accessibilityIdentifier = "PlayButton"; + play.accessibilityTraits = .button + + let pause = LNSystemBarButtonItem("pause.fill", scale: scale != .larger ? .init(rawValue: scale.rawValue + 1)! : scale, primaryAction: UIAction(handler: playPauseActionHandler)) + pause.accessibilityLabel = "Pause" + pause.accessibilityIdentifier = "PauseButton"; + pause.accessibilityTraits = .button + + let playPause = playerView.playbackSettings.isPlaying ? pause : play + + let next = LNSystemBarButtonItem("forward.fill", scale: backForwardScale, target: nil, action: nil) + next.accessibilityLabel = "Next Track" + next.accessibilityIdentifier = "NextButton"; + next.accessibilityTraits = .button + + let prev = LNSystemBarButtonItem("backward.fill", scale: backForwardScale, target: nil, action: nil) + prev.accessibilityLabel = "Previous Track" + prev.accessibilityIdentifier = "PrevButton"; + prev.accessibilityTraits = .button + + let more = LNSystemBarButtonItem("ellipsis", scale: backForwardScale, target: nil, action: nil) + more.accessibilityLabel = "More" + more.accessibilityIdentifier = "MoreButton"; + more.accessibilityTraits = .button + + if scale == .compact { + if traitCollection.horizontalSizeClass == .compact { + popupItem.leadingBarButtonItems = [playPause] + popupItem.trailingBarButtonItems = [more] + } else { + popupItem.leadingBarButtonItems = [prev, playPause, next] + popupItem.trailingBarButtonItems = [more] + } + } else { + if traitCollection.horizontalSizeClass == .compact { + popupItem.barButtonItems = [playPause, next] + } else { + popupItem.barButtonItems = [prev, playPause, next] + } + } + } + + override func viewDidMove(toPopupContainerContentView popupContentView: LNPopupContentView?) { + super.viewDidMove(toPopupContainerContentView: popupContentView) + + if popupContentView == nil { + timer?.invalidate() + timer = nil + } + } + + override func positionPopupCloseButton(_ popupCloseButton: LNPopupCloseButton) -> Bool { + #if targetEnvironment(macCatalyst) + return false + #else + self.popupCloseButton = popupCloseButton + self.view.setNeedsLayout() + return true + #endif + } + + override func viewDidLoad() { + super.viewDidLoad() + + updateBarItems(with: traitCollection) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + UIView.performWithoutAnimation { + view.alpha = 0.0 + } + + view.alpha = 1.0 + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + UIView.performWithoutAnimation { + view.alpha = 1.0 + } + + view.alpha = 0.0 + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if let popupCloseButton = popupCloseButton, popupCloseButton.superview != vibrancyView.contentView { + vibrancyView.contentView.addSubview(popupCloseButton) + + popupCloseButton.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + popupCloseButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + popupCloseButton.topAnchor.constraint(equalTo: vibrancyView.contentView.topAnchor, constant: 4), + ]) + } + } + + override func willTransition(to newCollection: UITraitCollection, with coordinator: any UIViewControllerTransitionCoordinator) { + super.willTransition(to: newCollection, with: coordinator) + + updateBarItems(with: newCollection) + } + + var songTitle: String = "" { + didSet { + popupItem.title = songTitle + playerView.playbackSettings.songTitle = songTitle + } + } + + var albumTitle: String = "" { + didSet { + if LNPopupBar.Style(rawValue: UserDefaults.settings.object(forKey: .barStyle) as? Int ?? 0)! == .compact { + popupItem.subtitle = albumTitle + } + playerView.playbackSettings.albumTitle = albumTitle + } + } + + var albumArt: UIImage = UIImage() { + didSet { + playerView.playbackSettings.albumArt = albumArt + popupItem.image = albumArt + popupItem.accessibilityImageLabel = NSLocalizedString("Album Art", comment: "") + } + } + + @objc required dynamic init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func _timerTicked(_ timer: Timer) { + defer { + popupItem.accessibilityProgressLabel = NSLocalizedString("Playback Progress", comment: "") + let totalTime = TimeInterval(250) + popupItem.accessibilityProgressValue = "\(accessibilityDateComponentsFormatter.string(from: TimeInterval(popupItem.progress) * totalTime)!) \(NSLocalizedString("of", comment: "")) \(accessibilityDateComponentsFormatter.string(from: totalTime)!)" + } + + guard playerView.playbackSettings.isPlaying && playerView.playbackSettings.progressEditedByUser == false else { + return + } + + playerView.playbackSettings.playbackProgress += 0.001 + popupItem.progress = playerView.playbackSettings.playbackProgress + + if popupItem.progress >= 1.0 { + timer.invalidate() + popupPresentationContainer?.dismissPopupBar(animated: true, completion: nil) + } + } +} + +#endif diff --git a/LNPopupControllerExample/LNPopupControllerExample/MusicScene/MusicCell.swift b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/MusicCell.swift new file mode 100644 index 0000000..8afabdd --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/MusicCell.swift @@ -0,0 +1,72 @@ +// +// MusicCell.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit + +class MusicCell: UITableViewCell { + let selectionEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) + + required init?(coder: NSCoder) { + super.init(coder: coder) + + selectionEffectView.frame = bounds + selectionEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + selectionEffectView.isHidden = true + addSubview(selectionEffectView) + sendSubviewToBack(selectionEffectView) + + selectionStyle = .none + } + + override func layoutSubviews() { + super.layoutSubviews() + + imageView?.layer.cornerRadius = 5 + imageView?.layer.cornerCurve = .continuous + + if UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .leftToRight { + imageView?.frame = CGRect(x: layoutMargins.left, y: bounds.height / 2 - 24, width: 48, height: 48) + + textLabel?.textAlignment = .left + textLabel?.lineBreakMode = .byTruncatingTail + textLabel?.frame = CGRect(x: imageView!.frame.maxX + 20, y: textLabel!.frame.minY, width: accessoryView!.frame.minX - imageView!.frame.maxX - 40, height: textLabel!.frame.height) + detailTextLabel?.textAlignment = .left + detailTextLabel?.lineBreakMode = .byTruncatingTail + detailTextLabel?.frame = CGRect(x: imageView!.frame.maxX + 20, y: detailTextLabel!.frame.minY, width: accessoryView!.frame.minX - imageView!.frame.maxX - 40, height: detailTextLabel!.frame.height) + + separatorInset = UIEdgeInsets(top: 0, left: textLabel!.frame.origin.x, bottom: 0, right: 0) + } else { + imageView?.frame = CGRect(x: contentView.bounds.width - layoutMargins.right - 48, y: bounds.height / 2 - 24, width: 48, height: 48) + + textLabel?.textAlignment = .right + textLabel?.lineBreakMode = .byTruncatingHead + textLabel?.frame = CGRect(x: 20, y: textLabel!.frame.minY, width: contentView.bounds.width - (2 * layoutMargins.right) - imageView!.bounds.width - 20, height: textLabel!.frame.height) + detailTextLabel?.textAlignment = .right + detailTextLabel?.lineBreakMode = .byTruncatingHead + detailTextLabel?.frame = CGRect(x: 20, y: detailTextLabel!.frame.minY, width: contentView.bounds.width - (2 * layoutMargins.right) - imageView!.bounds.width - 20, height: detailTextLabel!.frame.height) + + separatorInset = UIEdgeInsets(top: 0, left: textLabel!.frame.origin.x, bottom: 0, right: 0) + } + } + + override func setHighlighted(_ highlighted: Bool, animated: Bool) { + guard isHighlighted != highlighted else { + return + } + + super.setHighlighted(highlighted, animated: animated) + + selectionEffectView.alpha = highlighted ? 0.0 : 1.0 + selectionEffectView.isHidden = false + UIView.animate(withDuration: highlighted ? 0.0 : 0.35) { + self.selectionEffectView.alpha = highlighted ? 1.0 : 0.0 + } completion: { _ in + self.selectionEffectView.isHidden = highlighted == false + } + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/MusicScene/PortraitTabBarController.swift b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/PortraitTabBarController.swift new file mode 100644 index 0000000..c881269 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/MusicScene/PortraitTabBarController.swift @@ -0,0 +1,17 @@ +// +// PortraitTabBarController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit + +class PortraitTabBarController: UITabBarController { + + override var supportedInterfaceOrientations : UIInterfaceOrientationMask { + return .portrait + } + +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Settings/Base.lproj/Settings.storyboard b/LNPopupControllerExample/LNPopupControllerExample/Settings/Base.lproj/Settings.storyboard new file mode 100644 index 0000000..570647a --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Settings/Base.lproj/Settings.storyboard @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/AppDelegate.h b/LNPopupControllerExample/LNPopupControllerExample/Supporting/AppDelegate.h new file mode 100644 index 0000000..228ea8d --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/AppDelegate.h @@ -0,0 +1,16 @@ +// +// AppDelegate.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow* window; + +@end + diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/AppDelegate.m b/LNPopupControllerExample/LNPopupControllerExample/Supporting/AppDelegate.m new file mode 100644 index 0000000..a3140d7 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/AppDelegate.m @@ -0,0 +1,107 @@ +// +// AppDelegate.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "AppDelegate.h" +#import "SettingKeys.h" +@import ObjectiveC; + +@interface NSBundle () + +- (NSAttributedString *)localizedAttributedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName localization:(id)arg4; +@end + +@interface NSBundle (HebrewTransliteration) @end + +@implementation NSBundle (HebrewTransliteration) + +- (NSString *)_hebrew_localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName localizations:(id)arg4 +{ + return [self _hebrew_localizedStringForKey:key value:value table:tableName]; +} + +- (NSAttributedString *)_hebrew_localizedAttributedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName +{ + return [[NSAttributedString alloc] initWithString:[self _hebrew_localizedStringForKey:key value:value table:tableName]]; +} + +- (NSAttributedString *)_hebrew_localizedAttributedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName localization:(id)arg4 +{ + return [[NSAttributedString alloc] initWithString:[self _hebrew_localizedStringForKey:key value:value table:tableName]]; +} + +- (NSString *)_hebrew_localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName +{ + NSString* stringToTransliterate = value.length > 0 ? value : key; + stringToTransliterate = [stringToTransliterate stringByReplacingOccurrencesOfString:@"LNPopupController" withString:@"×�ֶלְ×�Ö¶× ï­„ï­‹ï­„×�ָפְּקוֹנְטְרוֹלֶר"]; + stringToTransliterate = [stringToTransliterate stringByReplacingOccurrencesOfString:@"Controller" withString:@"קוֹנְטְרוֹלֶר"]; + stringToTransliterate = [[stringToTransliterate stringByReplacingOccurrencesOfString:@"ll" withString:@"l"] stringByReplacingOccurrencesOfString:@"tt" withString:@"t"]; + + NSString* rv = [stringToTransliterate stringByApplyingTransform:NSStringTransformLatinToHebrew reverse:NO]; + + return rv; +} + ++ (void)load +{ + @autoreleasepool + { + if([NSUserDefaults.standardUserDefaults boolForKey:PopupSettingForceRTL] == NO) + { + return; + } + + Method m1 = class_getInstanceMethod(NSBundle.class, @selector(localizedStringForKey:value:table:)); + Method m2 = class_getInstanceMethod(NSBundle.class, @selector(_hebrew_localizedStringForKey:value:table:)); + method_exchangeImplementations(m1, m2); + + m1 = class_getInstanceMethod(NSBundle.class, @selector(localizedStringForKey:value:table:localizations:)); + m2 = class_getInstanceMethod(NSBundle.class, @selector(_hebrew_localizedStringForKey:value:table:localizations:)); + method_exchangeImplementations(m1, m2); + + m1 = class_getInstanceMethod(NSBundle.class, @selector(localizedAttributedStringForKey:value:table:)); + m2 = class_getInstanceMethod(NSBundle.class, @selector(_hebrew_localizedAttributedStringForKey:value:table:)); + method_exchangeImplementations(m1, m2); + + m1 = class_getInstanceMethod(NSBundle.class, @selector(localizedAttributedStringForKey:value:table:localization:)); + m2 = class_getInstanceMethod(NSBundle.class, @selector(_hebrew_localizedAttributedStringForKey:value:table:localization:)); + method_exchangeImplementations(m1, m2); + } +} + +@end + +@interface AppDelegate () + +@end + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +// self.window.layer.speed = 0.2; + + return YES; +} + +#pragma mark - UISceneSession lifecycle + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options +{ + UISceneConfiguration* config = [[UISceneConfiguration alloc] initWithName:@"LNPopupExample" sessionRole:connectingSceneSession.role]; + + + return config; +} + +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions +{ + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. +} + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AccentColor.colorset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..e12e779 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,15 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "universal", + "reference" : "systemPinkColor" + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..65e0789 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "filename" : "icon_1024.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Icon-dark.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "filename" : "Icon-tinted.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Icon-dark.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Icon-dark.png new file mode 100644 index 0000000..154a850 Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Icon-dark.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Icon-tinted.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Icon-tinted.png new file mode 100644 index 0000000..39e7d60 Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/Icon-tinted.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_1024.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/icon_1024.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_1024.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIcon.appiconset/icon_1024.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/Contents.json new file mode 100644 index 0000000..63885ac --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "icon_1024.png", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Icon-dark.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/Icon-dark.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/Icon-dark.png new file mode 100644 index 0000000..28f3456 Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/Icon-dark.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/icon_1024.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/icon_1024.png new file mode 100644 index 0000000..113b680 Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/AppIconPopupBar.imageset/icon_1024.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/demoAlbum.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/demoAlbum.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/demoAlbum.imageset/smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/demoAlbum.imageset/smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/gears.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/gears.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/gears.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/gears.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/gears.imageset/gears.pdf b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/gears.imageset/gears.pdf similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/gears.imageset/gears.pdf rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/gears.imageset/gears.pdf diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/genre-image-80s-hits.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/genre-image-80s-hits.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/genre-image-80s-hits@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/genre-image-80s-hits@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/genre-image-80s-hits@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre1.imageset/genre-image-80s-hits@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/genre-image-country-hits.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/genre-image-country-hits.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/genre-image-country-hits@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/genre-image-country-hits@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/genre-image-country-hits@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre10.imageset/genre-image-country-hits@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/genre-image-dance.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/genre-image-dance.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/genre-image-dance@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/genre-image-dance@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/genre-image-dance@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre11.imageset/genre-image-dance@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/genre-image-decades.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/genre-image-decades.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/genre-image-decades@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/genre-image-decades@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/genre-image-decades@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre12.imageset/genre-image-decades@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/genre-image-electronic.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/genre-image-electronic.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/genre-image-electronic@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/genre-image-electronic@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/genre-image-electronic@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre13.imageset/genre-image-electronic@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/genre-image-gospel.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/genre-image-gospel.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/genre-image-gospel@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/genre-image-gospel@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/genre-image-gospel@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre14.imageset/genre-image-gospel@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/genre-image-hip-hop.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/genre-image-hip-hop.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/genre-image-hip-hop@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/genre-image-hip-hop@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/genre-image-hip-hop@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre15.imageset/genre-image-hip-hop@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/genre-image-indie.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/genre-image-indie.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/genre-image-indie@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/genre-image-indie@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/genre-image-indie@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre16.imageset/genre-image-indie@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17-expanded.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17-expanded.imageset/Contents.json new file mode 100644 index 0000000..7e22dda --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17-expanded.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "genre-image-jazz-expanded.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17-expanded.imageset/genre-image-jazz-expanded.jpg b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17-expanded.imageset/genre-image-jazz-expanded.jpg new file mode 100644 index 0000000..b3ba1e9 Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17-expanded.imageset/genre-image-jazz-expanded.jpg differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/genre-image-jazz.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/genre-image-jazz.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/genre-image-jazz@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/genre-image-jazz@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/genre-image-jazz@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre17.imageset/genre-image-jazz@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/genre-image-kids-and-family.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/genre-image-kids-and-family.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/genre-image-latin-hits.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/genre-image-latin-hits.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/genre-image-latin-hits@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/genre-image-latin-hits@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/genre-image-latin-hits@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre19.imageset/genre-image-latin-hits@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/genre-image-alternative.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/genre-image-alternative.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/genre-image-alternative@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/genre-image-alternative@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/genre-image-alternative@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre2.imageset/genre-image-alternative@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/genre-image-metal.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/genre-image-metal.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/genre-image-metal@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/genre-image-metal@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/genre-image-metal@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre20.imageset/genre-image-metal@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/genre-image-modern-rock.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/genre-image-modern-rock.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/genre-image-modern-rock@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/genre-image-modern-rock@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/genre-image-modern-rock@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre21.imageset/genre-image-modern-rock@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/genre-image-pop-gold.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/genre-image-pop-gold.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/genre-image-pop-gold@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/genre-image-pop-gold@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/genre-image-pop-gold@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre22.imageset/genre-image-pop-gold@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/genre-image-pop-hits.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/genre-image-pop-hits.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/genre-image-pop-hits@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/genre-image-pop-hits@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/genre-image-pop-hits@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre23.imageset/genre-image-pop-hits@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/genre-image-randb.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/genre-image-randb.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/genre-image-randb@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/genre-image-randb@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/genre-image-randb@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre24.imageset/genre-image-randb@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/genre-image-reggae.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/genre-image-reggae.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/genre-image-reggae@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/genre-image-reggae@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/genre-image-reggae@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre25.imageset/genre-image-reggae@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/genre-image-regional-mexican.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/genre-image-regional-mexican.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/genre-image-smooth-pop.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/genre-image-smooth-pop.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/genre-image-blues.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/genre-image-blues.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/genre-image-blues@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/genre-image-blues@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/genre-image-blues@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre3.imageset/genre-image-blues@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/genre-image-world-hits.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/genre-image-world-hits.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/genre-image-world-hits@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/genre-image-world-hits@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/genre-image-world-hits@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre30.imageset/genre-image-world-hits@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/genre-image-christian.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/genre-image-christian.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/genre-image-christian@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/genre-image-christian@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/genre-image-christian@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre4.imageset/genre-image-christian@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/genre-image-classic-alt.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/genre-image-classic-alt.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/genre-image-classic-alt@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/genre-image-classic-alt@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/genre-image-classic-alt@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre5.imageset/genre-image-classic-alt@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/genre-image-classic-country.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/genre-image-classic-country.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/genre-image-classic-country@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/genre-image-classic-country@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/genre-image-classic-country@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre6.imageset/genre-image-classic-country@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/genre-image-classic-randb.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/genre-image-classic-randb.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/genre-image-classic-randb@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/genre-image-classic-randb@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/genre-image-classic-randb@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre7.imageset/genre-image-classic-randb@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/genre-image-classic-rock.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/genre-image-classic-rock.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/genre-image-classic-rock@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/genre-image-classic-rock@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/genre-image-classic-rock@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre8.imageset/genre-image-classic-rock@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/Contents.json rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/genre-image-classical.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/genre-image-classical.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@2x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/genre-image-classical@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@2x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/genre-image-classical@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@3x.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/genre-image-classical@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@3x.png rename to LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre9.imageset/genre-image-classical@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/Contents.json new file mode 100644 index 0000000..fc7803d --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "genre_white.png", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "genre_black.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/genre_black.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/genre_black.png new file mode 100644 index 0000000..fcf9d4f Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/genre_black.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/genre_white.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/genre_white.png new file mode 100644 index 0000000..4e3f2b3 Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/genre_white.imageset/genre_white.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/statusBarMask.imageset/Contents.json b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/statusBarMask.imageset/Contents.json new file mode 100644 index 0000000..43843f3 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/statusBarMask.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "mask.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/statusBarMask.imageset/mask.png b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/statusBarMask.imageset/mask.png new file mode 100644 index 0000000..93e5a5c Binary files /dev/null and b/LNPopupControllerExample/LNPopupControllerExample/Supporting/Assets.xcassets/statusBarMask.imageset/mask.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/LNPopupControllerExample-Bridging-Header.h b/LNPopupControllerExample/LNPopupControllerExample/Supporting/LNPopupControllerExample-Bridging-Header.h new file mode 100644 index 0000000..d89cc0c --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/LNPopupControllerExample-Bridging-Header.h @@ -0,0 +1,25 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#if LNPOPUP +@import LNPopupController; +#endif +#import "LoremIpsum.h" +#import "RandomColors.h" +#import "SafeSystemImages.h" +#import "SettingKeys.h" +#import "DemoPopupContentViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface UIBlurEffect () + ++ (instancetype)_effectWithStyle:(UIBlurEffectStyle)arg1 tintColor:(UIColor*)arg2 invertAutomaticStyle:(BOOL)arg3; ++ (instancetype)_effectWithTintColor:(UIColor*)arg1; ++ (instancetype)effectWithBlurRadius:(CGFloat)arg1; ++ (instancetype)effectWithVariableBlurRadius:(CGFloat)arg1 imageMask:(UIImage*)arg2 API_AVAILABLE(ios(17.0)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/LaunchScreen.storyboard b/LNPopupControllerExample/LNPopupControllerExample/Supporting/LaunchScreen.storyboard new file mode 100644 index 0000000..7e626ec --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/LaunchScreen.storyboard @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/SceneDelegate.h b/LNPopupControllerExample/LNPopupControllerExample/Supporting/SceneDelegate.h new file mode 100644 index 0000000..85110c9 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/SceneDelegate.h @@ -0,0 +1,17 @@ +// +// SceneDelegate.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2019-08-21. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +@interface SceneDelegate : UIResponder + +@property (strong, nonatomic) UIWindow* window; +@property (weak, nonatomic) UIWindowScene* windowScene; + +@end + diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/SceneDelegate.m b/LNPopupControllerExample/LNPopupControllerExample/Supporting/SceneDelegate.m new file mode 100644 index 0000000..2fa51c9 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/SceneDelegate.m @@ -0,0 +1,60 @@ +#import "SceneDelegate.h" + +@interface SceneDelegate () + +@end + +@implementation SceneDelegate + +- (void)scene:(UIWindowScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions +{ + self.windowScene = scene; + +#if TARGET_OS_MACCATALYST + scene.sizeRestrictions.maximumSize = CGSizeMake(DBL_MAX, DBL_MAX); + scene.titlebar.toolbar = nil; + + if([self.window.rootViewController isKindOfClass:UISplitViewController.class]) + { + UISplitViewController* split = (id)self.window.rootViewController; + split.primaryBackgroundStyle = UISplitViewControllerBackgroundStyleSidebar; + } +#endif +} + +- (void)sceneDidDisconnect:(UIScene *)scene +{ + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + + self.windowScene = nil; +} + + +- (void)sceneDidBecomeActive:(UIScene *)scene { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. +} + + +- (void)sceneWillResignActive:(UIScene *)scene { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). +} + + +- (void)sceneWillEnterForeground:(UIScene *)scene { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. +} + + +- (void)sceneDidEnterBackground:(UIScene *)scene { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. +} + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/Supporting/main.m b/LNPopupControllerExample/LNPopupControllerExample/Supporting/main.m new file mode 100644 index 0000000..a174fa7 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Supporting/main.m @@ -0,0 +1,37 @@ +// +// main.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import +#import "AppDelegate.h" +@import ObjectiveC; + +#if TARGET_OS_MACCATALYST +@interface NSObject (ZZZ) @end +@implementation NSObject (ZZZ) + ++ (void)load +{ + Class cls = NSClassFromString(@"UIFocusRingManager"); + Method m1 = class_getClassMethod(cls, NSSelectorFromString(@"moveRingToFocusItem:")); + Method m2 = class_getClassMethod(NSObject.class, @selector(__ln_moveRingToFocusItem:)); + method_exchangeImplementations(m1, m2); +} + ++ (void)__ln_moveRingToFocusItem:(id)arg1 +{ + +} + +@end +#endif + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/Base.lproj/Main.storyboard b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/Base.lproj/Main.storyboard new file mode 100644 index 0000000..7f9cd85 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/Base.lproj/Main.storyboard @@ -0,0 +1,784 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoGallery.h b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoGallery.h new file mode 100644 index 0000000..802b155 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoGallery.h @@ -0,0 +1,14 @@ +// +// DemoGallery.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2020-11-01. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +@import UIKit; + +NS_ASSUME_NONNULL_BEGIN + + +NS_ASSUME_NONNULL_END diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoGallery.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoGallery.m new file mode 100644 index 0000000..97d2de5 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoGallery.m @@ -0,0 +1,101 @@ +// +// DemoGallery.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2020-11-01. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "DemoGallery.h" + +#if LNPOPUP +@import LNPopupController; +#import "IntroWebViewController.h" +#import "LNPopupDemoContextMenuInteraction.h" +#endif + +@interface DemoGalleryToolbar : UIToolbar @end +@implementation DemoGalleryToolbar @end + +@interface SizeClassGalleryCell : UITableViewCell + +@property (nonatomic, getter=isEnabled) BOOL enabled; + +@end + +@implementation SizeClassGalleryCell + +-(void)setEnabled:(BOOL)enabled +{ + if(enabled) + { + self.textLabel.textColor = UIColor.labelColor; + self.selectionStyle = UITableViewCellSelectionStyleDefault; + } + else + { + self.textLabel.textColor = UIColor.secondaryLabelColor; + self.selectionStyle = UITableViewCellSelectionStyleNone; + } +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection +{ + [super traitCollectionDidChange:previousTraitCollection]; + + [self setEnabled:self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular]; +} + +@end + +@import SafariServices; + +@interface DemoGalleryController : UITableViewController@end +@implementation DemoGalleryController +{ +#if LNPOPUP + IntroWebViewController* _demoVC; +#endif +} + +- (IBAction)unwindToGallery:(UIStoryboardSegue *)unwindSegue { } + +- (void)viewDidLoad +{ + [super viewDidLoad]; + +#if LNPOPUP + _demoVC = [IntroWebViewController new]; + + self.navigationController.popupBar.barStyle = LNPopupBarStyleFloating; + self.navigationController.popupBar.standardAppearance.marqueeScrollDelay = 0.0; + self.navigationController.popupBar.standardAppearance.marqueeScrollEnabled = YES; + + self.navigationController.view.tintColor = self.navigationController.navigationBar.tintColor; + [self.navigationController presentPopupBarWithContentViewController:_demoVC animated:NO completion:nil]; + + [self.navigationController.popupBar addInteraction:[LNPopupDemoContextMenuInteraction new]]; +#endif +} + +- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender +{ + if([identifier hasPrefix:@"split"] && self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) + { + [self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:NO]; + + return NO; + } + + return YES; +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + if(segue.destinationViewController.modalPresentationStyle != UIModalPresentationFullScreen) + { + [self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:YES]; + } +} + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoPopupContentViewController.h b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoPopupContentViewController.h new file mode 100644 index 0000000..f7fc693 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoPopupContentViewController.h @@ -0,0 +1,15 @@ +// +// DemoPopupContentViewController.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2016-08-06. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +extern void LNApplyTitleWithSettings(UIViewController* vc) NS_SWIFT_NAME(LNApplyTitleWithSettings(to:)); + +@interface DemoPopupContentViewController : UIViewController + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoPopupContentViewController.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoPopupContentViewController.m new file mode 100644 index 0000000..8ced2c4 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoPopupContentViewController.m @@ -0,0 +1,546 @@ +// +// DemoPopupContentViewController.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2016-08-06. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#if LNPOPUP +#import "DemoPopupContentViewController.h" +#import "SettingKeys.h" +#import "RandomColors.h" +#import "LoremIpsum.h" +#import "SafeSystemImages.h" + +@import LNPopupController; + +void LNApplyTitleWithSettings(UIViewController* self) +{ + uint32_t titleLowerLimit = 2; + uint32_t titleUpperLimit = 5; + + uint32_t subtitleLowerLimit = 4; + uint32_t subtitleUpperLimit = 16; + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingMarqueeEnabled] == YES) + { + subtitleLowerLimit = 10; + } + + self.popupItem.title = [[LoremIpsum wordsWithNumber:arc4random_uniform(titleUpperLimit - titleLowerLimit) + titleLowerLimit] capitalizedString]; + self.popupItem.subtitle = [[LoremIpsum wordsWithNumber:arc4random_uniform(subtitleUpperLimit - subtitleLowerLimit) + subtitleLowerLimit] valueForKey:@"li_stringByCapitalizingFirstLetter"]; + + if([NSUserDefaults.standardUserDefaults boolForKey:PopupSettingForceRTL]) + { + self.popupItem.title = [self.popupItem.title stringByApplyingTransform:NSStringTransformLatinToHebrew reverse:NO]; + self.popupItem.subtitle = [self.popupItem.subtitle stringByApplyingTransform:NSStringTransformLatinToHebrew reverse:NO]; + } + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingDisableDemoSceneColors] == NO) + { + self.popupItem.image = [UIImage imageNamed:@"genre17"]; + } + else + { + self.popupItem.image = [UIImage imageNamed:@"genre_white"]; + } + self.popupItem.progress = (float) arc4random() / UINT32_MAX; +// self.popupItem.progress = 1.0; +} + +@interface DemoPopupContentView : UIView @end +@implementation DemoPopupContentView + +- (void)setFrame:(CGRect)frame +{ +// NSLog(@"Frame: %@", @(frame)); + [super setFrame:frame]; +} + +@end + +@interface DemoPopupContentViewController () @end +@implementation DemoPopupContentViewController +{ + NSInteger _lastStyle; + LNPopupImageView* _preferredTransitionView; + UIView* _genericTransitionView; +} + +- (void)loadView +{ + self.view = [DemoPopupContentView new]; +} + +- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator +{ + [coordinator animateAlongsideTransitionInView:self.popupPresentationContainerViewController.view animation:^(id _Nonnull context) { + [self _setPopupItemButtonsWithTraitCollection:newCollection animated:context.animated]; + [self updateTransitionViewShadowColor]; + } completion:nil]; + + [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; +} + +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator +{ + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; +} + +- (void)_updateBackgroundColor +{ + if([NSUserDefaults.settingDefaults integerForKey:PopupSettingTransitionType] == 2) + { + return; + } + + if(self.view.traitCollection.userInterfaceStyle != _lastStyle) + { + _lastStyle = self.view.traitCollection.userInterfaceStyle; + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingDisableDemoSceneColors] == NO) + { + self.view.backgroundColor = LNSeedAdaptiveInvertedColor(@"Popup"); + } + else + { + self.view.backgroundColor = UIColor.labelColor; + } + } + + [self setNeedsStatusBarAppearanceUpdate]; +} + +- (void)button:(UIBarButtonItem*)button +{ + NSLog(@"✓"); +} + +- (void)_setPopupItemButtonsWithTraitCollection:(UITraitCollection*)collection animated:(BOOL)animated +{ + LNSystemImageScale scale; + LNSystemImageScale backForwardScale; + if([[NSUserDefaults.settingDefaults objectForKey:PopupSettingBarStyle] unsignedIntegerValue] == LNPopupBarStyleCompact) + { + scale = LNSystemImageScaleCompact; + backForwardScale = LNSystemImageScaleCompact; + } + else if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad && collection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) + { + scale = LNSystemImageScaleLarger; + backForwardScale = LNSystemImageScaleLarge; + } + else + { + scale = LNSystemImageScaleNormal; + backForwardScale = LNSystemImageScaleNormal; + } + + UIBarButtonItem* play = LNSystemBarButtonItem(@"pause.fill", scale != LNSystemImageScaleLarger ? scale + 1 : scale, self, @selector(button:)); + play.accessibilityLabel = NSLocalizedString(@"Pause", @""); + play.accessibilityIdentifier = @"PauseButton"; + play.accessibilityTraits = UIAccessibilityTraitButton; + + UIBarButtonItem* stop = LNSystemBarButtonItem(@"stop.fill", scale, self, @selector(button:)); + stop.accessibilityLabel = NSLocalizedString(@"Stop", @""); + stop.accessibilityIdentifier = @"StopButton"; + stop.accessibilityTraits = UIAccessibilityTraitButton; + + UIBarButtonItem* next = LNSystemBarButtonItem(@"forward.fill", backForwardScale, self, @selector(button:)); + next.accessibilityLabel = NSLocalizedString(@"Next Track", @""); + next.accessibilityIdentifier = @"NextButton"; + next.accessibilityTraits = UIAccessibilityTraitButton; + + UIBarButtonItem* prev = LNSystemBarButtonItem(@"backward.fill", backForwardScale, self, @selector(button:)); + prev.accessibilityLabel = NSLocalizedString(@"Previous Track", @""); + prev.accessibilityIdentifier = @"PrevButton"; + prev.accessibilityTraits = UIAccessibilityTraitButton; + + UIBarButtonItem* more = LNSystemBarButtonItem(@"ellipsis", scale, self, @selector(button:)); + prev.accessibilityLabel = NSLocalizedString(@"More", @""); + prev.accessibilityIdentifier = @"MoreButton"; + prev.accessibilityTraits = UIAccessibilityTraitButton; + + if(scale == LNSystemImageScaleCompact) + { + if(collection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) + { + [self.popupItem setLeadingBarButtonItems:@[ play ] animated:animated]; + [self.popupItem setTrailingBarButtonItems:@[ more ] animated:animated]; + } + else + { + [self.popupItem setLeadingBarButtonItems:@[ prev, play, next ] animated:animated]; + [self.popupItem setTrailingBarButtonItems:@[ more ] animated:animated]; + } + } + else + { + if(collection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) + { + [self.popupItem setBarButtonItems:@[ play, next ] animated:NO]; + } + else + { + [self.popupItem setBarButtonItems:@[ prev, play, next ] animated:NO]; + } + } +} + +- (BOOL)prefersStatusBarHidden +{ + return self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact; +} + +- (void)updateTransitionViewShadowColor +{ + if(_preferredTransitionView != nil) + { + NSShadow* shadow = _preferredTransitionView.shadow.copy; + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingEnableCustomizations]) + { + shadow.shadowColor = UIColor.cyanColor; + } + else + { + shadow.shadowColor = [UIColor.blackColor colorWithAlphaComponent:0.333333]; + } + + _preferredTransitionView.shadow = shadow; + } + else if(_genericTransitionView != nil) + { + _genericTransitionView.layer.shadowOffset = CGSizeZero; + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingEnableCustomizations]) + { + _genericTransitionView.layer.shadowColor = UIColor.yellowColor.CGColor; + _genericTransitionView.layer.shadowOpacity = 1.0; + } + else + { + _genericTransitionView.layer.shadowColor = [UIColor.blackColor colorWithAlphaComponent:0.333333].CGColor; + _genericTransitionView.layer.shadowOpacity = 1.0; + } + } +} + +- (void)viewDidMoveToPopupContainerContentView:(LNPopupContentView *)popupContentView +{ + [super viewDidMoveToPopupContainerContentView:popupContentView]; + + if(popupContentView == nil) + { + return; + } + + LNApplyTitleWithSettings(self); + + if([NSUserDefaults.settingDefaults integerForKey:PopupSettingTransitionType] == 0) + { + NSShadow* shadow = [NSShadow new]; + shadow.shadowBlurRadius = 15.0; + + _preferredTransitionView = [[LNPopupImageView alloc] initWithImage:self.popupItem.image]; + _preferredTransitionView.shadow = shadow; + _preferredTransitionView.cornerRadius = 30.0; + _preferredTransitionView.translatesAutoresizingMaskIntoConstraints = NO; + [self updateTransitionViewShadowColor]; + + NSLayoutConstraint* leading = [_preferredTransitionView.leadingAnchor constraintGreaterThanOrEqualToAnchor:self.view.layoutMarginsGuide.leadingAnchor]; + leading.priority = UILayoutPriorityDefaultHigh; + NSLayoutConstraint* trailing = [_preferredTransitionView.trailingAnchor constraintGreaterThanOrEqualToAnchor:self.view.layoutMarginsGuide.trailingAnchor]; + trailing.priority = UILayoutPriorityDefaultHigh; + + [self.view addSubview:_preferredTransitionView]; + [NSLayoutConstraint activateConstraints:@[ + leading, + trailing, + [_preferredTransitionView.widthAnchor constraintLessThanOrEqualToConstant:400], + [_preferredTransitionView.centerXAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.centerXAnchor], + [_preferredTransitionView.topAnchor constraintGreaterThanOrEqualToAnchor:popupContentView.popupCloseButton.bottomAnchor constant:20], + [_preferredTransitionView.widthAnchor constraintEqualToAnchor:_preferredTransitionView.heightAnchor], + ]]; + } + else if([NSUserDefaults.settingDefaults integerForKey:PopupSettingTransitionType] == 1) + { + UIImageView* transitionImageView = [UIImageView new]; + transitionImageView.layer.cornerRadius = 30.0; + transitionImageView.layer.cornerCurve = kCACornerCurveContinuous; + transitionImageView.layer.masksToBounds = YES; + transitionImageView.translatesAutoresizingMaskIntoConstraints = NO; + + _genericTransitionView = [UIView new]; + _genericTransitionView.layer.shadowRadius = 15.0; + _genericTransitionView.translatesAutoresizingMaskIntoConstraints = NO; + [self updateTransitionViewShadowColor]; + + [_genericTransitionView addSubview:transitionImageView]; + [NSLayoutConstraint activateConstraints:@[ + [_genericTransitionView.leadingAnchor constraintEqualToAnchor:transitionImageView.leadingAnchor], + [_genericTransitionView.trailingAnchor constraintEqualToAnchor:transitionImageView.trailingAnchor], + [_genericTransitionView.topAnchor constraintEqualToAnchor:transitionImageView.topAnchor], + [_genericTransitionView.bottomAnchor constraintEqualToAnchor:transitionImageView.bottomAnchor], + ]]; + + + NSLayoutConstraint* leading = [_genericTransitionView.leadingAnchor constraintGreaterThanOrEqualToAnchor:self.view.layoutMarginsGuide.leadingAnchor]; + leading.priority = UILayoutPriorityDefaultHigh; + NSLayoutConstraint* trailing = [_genericTransitionView.trailingAnchor constraintGreaterThanOrEqualToAnchor:self.view.layoutMarginsGuide.trailingAnchor]; + trailing.priority = UILayoutPriorityDefaultHigh; + + [self.view addSubview:_genericTransitionView]; + [NSLayoutConstraint activateConstraints:@[ + leading, + trailing, + [_genericTransitionView.widthAnchor constraintLessThanOrEqualToConstant:400], + [_genericTransitionView.centerXAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.centerXAnchor], + [_genericTransitionView.topAnchor constraintGreaterThanOrEqualToAnchor:popupContentView.popupCloseButton.bottomAnchor constant:20], + [_genericTransitionView.widthAnchor constraintEqualToAnchor:_genericTransitionView.heightAnchor], + ]]; + + transitionImageView.image = self.popupItem.image; + } + else if([NSUserDefaults.settingDefaults integerForKey:PopupSettingTransitionType] == 2) + { + UIImageView* backgroundView = [[LNPopupImageView alloc] initWithImage:[UIImage imageNamed:@"genre17-expanded"]]; + backgroundView.translatesAutoresizingMaskIntoConstraints = NO; + backgroundView.contentMode = UIViewContentModeScaleAspectFill; + backgroundView.clipsToBounds = YES; + + [self.view addSubview:backgroundView]; + [NSLayoutConstraint activateConstraints:@[ + [backgroundView.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [backgroundView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [backgroundView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [backgroundView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + ]]; + + _genericTransitionView = backgroundView; + + self.view.backgroundColor = UIColor.blackColor; + + self.popupPresentationContainerViewController.popupBar.imageView.contentMode = UIViewContentModeScaleToFill; + } + else + { + UILabel* topLabel = [UILabel new]; + topLabel.text = NSLocalizedString(@"Top", @""); + topLabel.textColor = [UIColor systemBackgroundColor]; + topLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + topLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:topLabel]; + + NSLayoutConstraint* center = [topLabel.centerXAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.centerXAnchor]; + center.priority = 500; + [NSLayoutConstraint activateConstraints:@[ + [topLabel.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], + center, + [topLabel.leadingAnchor constraintGreaterThanOrEqualToAnchor:popupContentView.popupCloseButton.trailingAnchor constant:8], + ]]; + + UILabel* bottomLabel = [UILabel new]; + bottomLabel.text = NSLocalizedString(@"Bottom", @""); + bottomLabel.textColor = [UIColor systemBackgroundColor]; + bottomLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + bottomLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:bottomLabel]; + [NSLayoutConstraint activateConstraints:@[ + [bottomLabel.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], + [bottomLabel.centerXAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.centerXAnchor] + ]]; + + UILabel* leadingMarginLabel = [UILabel new]; + leadingMarginLabel.text = NSLocalizedString(@"|-Leading (Margin)", @""); + leadingMarginLabel.textAlignment = NSTextAlignmentLeft; + leadingMarginLabel.textColor = [UIColor systemBackgroundColor]; + leadingMarginLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + leadingMarginLabel.adjustsFontForContentSizeCategory = YES; + // leadingMarginLabel.adjustsFontSizeToFitWidth = YES; + leadingMarginLabel.numberOfLines = 0; + leadingMarginLabel.lineBreakMode = NSLineBreakByWordWrapping; + leadingMarginLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:leadingMarginLabel]; + [NSLayoutConstraint activateConstraints:@[ + [leadingMarginLabel.leadingAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.leadingAnchor], + [leadingMarginLabel.topAnchor constraintEqualToAnchor:topLabel.bottomAnchor constant:60] + ]]; + + UILabel* trailingMarginLabel = [UILabel new]; + trailingMarginLabel.text = NSLocalizedString(@"Trailing (Margin)-|", @""); + trailingMarginLabel.textAlignment = NSTextAlignmentRight; + trailingMarginLabel.textColor = [UIColor systemBackgroundColor]; + trailingMarginLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + trailingMarginLabel.adjustsFontForContentSizeCategory = YES; + // trailingMarginLabel.adjustsFontSizeToFitWidth = YES; + trailingMarginLabel.numberOfLines = 0; + trailingMarginLabel.lineBreakMode = NSLineBreakByWordWrapping; + trailingMarginLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:trailingMarginLabel]; + [NSLayoutConstraint activateConstraints:@[ + [trailingMarginLabel.trailingAnchor constraintEqualToAnchor:self.view.layoutMarginsGuide.trailingAnchor], + [trailingMarginLabel.topAnchor constraintEqualToAnchor:topLabel.bottomAnchor constant:60], + [trailingMarginLabel.leadingAnchor constraintGreaterThanOrEqualToAnchor:leadingMarginLabel.trailingAnchor constant:8], + [trailingMarginLabel.widthAnchor constraintEqualToAnchor:leadingMarginLabel.widthAnchor] + ]]; + + UILabel* leadingSafeAreaLabel = [UILabel new]; + leadingSafeAreaLabel.text = NSLocalizedString(@"|-Leading (Safe Area)", @""); + leadingSafeAreaLabel.textAlignment = NSTextAlignmentLeft; + leadingSafeAreaLabel.textColor = [UIColor systemBackgroundColor]; + leadingSafeAreaLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + leadingSafeAreaLabel.adjustsFontForContentSizeCategory = YES; + // leadingSafeAreaLabel.adjustsFontSizeToFitWidth = YES; + leadingSafeAreaLabel.numberOfLines = 0; + leadingSafeAreaLabel.lineBreakMode = NSLineBreakByWordWrapping; + leadingSafeAreaLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:leadingSafeAreaLabel]; + [NSLayoutConstraint activateConstraints:@[ + [leadingSafeAreaLabel.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor], + [leadingSafeAreaLabel.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:0] + ]]; + + UILabel* trailingSafeAreaLabel = [UILabel new]; + trailingSafeAreaLabel.text = NSLocalizedString(@"Trailing (Safe Area)-|", @""); + trailingSafeAreaLabel.textAlignment = NSTextAlignmentRight; + trailingSafeAreaLabel.textColor = [UIColor systemBackgroundColor]; + trailingSafeAreaLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + trailingSafeAreaLabel.adjustsFontForContentSizeCategory = YES; + // trailingSafeAreaLabel.adjustsFontSizeToFitWidth = YES; + trailingSafeAreaLabel.numberOfLines = 0; + trailingSafeAreaLabel.lineBreakMode = NSLineBreakByWordWrapping; + trailingSafeAreaLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:trailingSafeAreaLabel]; + [NSLayoutConstraint activateConstraints:@[ + [trailingSafeAreaLabel.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor], + [trailingSafeAreaLabel.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:0], + [trailingSafeAreaLabel.leadingAnchor constraintGreaterThanOrEqualToAnchor:leadingSafeAreaLabel.trailingAnchor constant:8], + [trailingSafeAreaLabel.widthAnchor constraintEqualToAnchor:leadingSafeAreaLabel.widthAnchor] + ]]; + + self.popupItem.accessibilityLabel = NSLocalizedString(@"Custom popup bar accessibility label", @""); + self.popupItem.accessibilityHint = NSLocalizedString(@"Custom popup bar accessibility hint", @""); + + } + + [self _updateBackgroundColor]; + +// UIButton* customCloseButton = [UIButton buttonWithType:UIButtonTypeSystem]; +// [customCloseButton setTitle:NSLocalizedString(@"Custom Close Button", @"") forState:UIControlStateNormal]; +// customCloseButton.translatesAutoresizingMaskIntoConstraints = NO; +// [customCloseButton setTitleColor:UIColor.systemBackgroundColor forState:UIControlStateNormal]; +// customCloseButton.pointerInteractionEnabled = YES; +// [customCloseButton addTarget:self action:@selector(_closePopup) forControlEvents:UIControlEventTouchUpInside]; +// [self.view addSubview:customCloseButton]; +// [NSLayoutConstraint activateConstraints:@[ +// [self.view.safeAreaLayoutGuide.centerXAnchor constraintEqualToAnchor:customCloseButton.centerXAnchor], +// [self.view.safeAreaLayoutGuide.centerYAnchor constraintEqualToAnchor:customCloseButton.centerYAnchor], +// ]]; +} + +- (nullable UIView*)viewForPopupTransitionFromPresentationState:(LNPopupPresentationState)fromState toPresentationState:(LNPopupPresentationState)toState +{ + switch([NSUserDefaults.settingDefaults integerForKey:PopupSettingTransitionType]) + { + case 0: + //Automatic discovery will find the LNPopupImageView in our content view. + return [super viewForPopupTransitionFromPresentationState:fromState toPresentationState:toState]; + case 1: + case 2: + return _genericTransitionView; + default: + return nil; + } +} + +- (void)_closePopup +{ + [self.popupPresentationContainerViewController closePopupAnimated:YES completion:nil]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + +// if([NSUserDefaults.settingDefaults boolForKey:PopupSettingEnableTransition] == NO) +// { +// return; +// } +// +// [UIView performWithoutAnimation:^{ +// self.view.alpha = 0.0; +// }]; +// +// self.view.alpha = 1.0; +} + +- (void)viewIsAppearing:(BOOL)animated +{ + [super viewIsAppearing:animated]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + +// if([NSUserDefaults.settingDefaults boolForKey:PopupSettingEnableTransition] == NO) +// { +// return; +// } +// +// [UIView performWithoutAnimation:^{ +// self.view.alpha = 1.0; +// }]; +// +// self.view.alpha = 0.0; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; +} + +- (void)viewSafeAreaInsetsDidChange +{ + [super viewSafeAreaInsetsDidChange]; +} + +- (void)viewLayoutMarginsDidChange +{ + [super viewLayoutMarginsDidChange]; +} + +- (void)dealloc +{ + +} + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + if([NSUserDefaults.settingDefaults integerForKey:PopupSettingTransitionType] == 2) + { + return UIStatusBarStyleLightContent; + } + + return self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight ? UIStatusBarStyleLightContent : UIStatusBarStyleDarkContent; +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation +{ + return UIStatusBarAnimationFade;//Slide; +} + +- (BOOL)prefersHomeIndicatorAutoHidden +{ + return YES; +} + +@end + +#endif diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.h b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.h new file mode 100644 index 0000000..5f54f5c --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.h @@ -0,0 +1,15 @@ +// +// DemoViewController.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +@interface DemoViewController : UIViewController + + +@end + diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.m new file mode 100644 index 0000000..d9fbde5 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/DemoViewController.m @@ -0,0 +1,679 @@ +// +// DemoViewController.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#if LNPOPUP +@import LNPopupController; +#import +#endif +#import "DemoViewController.h" +#import "DemoPopupContentViewController.h" +#import "RandomColors.h" +#import "SettingKeys.h" +#import "LNSplitViewController.h" +#if LNPOPUP +#import "LNPopupControllerExample-Swift.h" +#endif +#import "LNPopupDemoContextMenuInteraction.h" +#import "LNPopupControllerExample-Bridging-Header.h" +@import UIKit; + +@interface UIImage () + ++ (instancetype)_systemImageNamed:(NSString*)arg1; + +@end + +@interface DemoView : UIView @end + +@implementation DemoView + +- (void)willMoveToWindow:(UIWindow *)newWindow +{ + [super willMoveToWindow:newWindow]; +} + +- (void)didMoveToWindow +{ + [super didMoveToWindow]; +} + +@end + +@interface DemoViewController () +#if LNPOPUP +< LNPopupPresentationDelegate > +#endif + +@property (nonatomic, strong) NSString* colorSeedString; +@property (nonatomic) NSInteger colorSeedCount; + +@end + +@implementation DemoViewController +{ + __weak IBOutlet UIButton *_galleryButton; + __weak IBOutlet UIButton *_nextButton; + + __weak IBOutlet UIBarButtonItem *_barStyleButton; + __weak IBOutlet UIBarButtonItem *_hideTabBarButton; + + __weak IBOutlet UIButton* _showPopupBarButton; + __weak IBOutlet UIButton* _hidePopupBarButton; + + BOOL _alreadyPresentedAutomatically; +} + +- (UITabBarItem *)tabBarItem +{ + if(@available(iOS 18.0, *)) + { + if(self.tab != nil) + { + return super.tabBarItem; + } + } + + if(self.tabBarController != nil) + { + UIViewController* target = self; + if(self.navigationController != nil) + { + target = self.navigationController; + } + + //This is safe even with the UITab API, because this will be accessed very early on, when loaded from storyboard. + super.tabBarItem.image = [UIImage systemImageNamed:[NSString stringWithFormat:@"%lu.square.fill", [self.tabBarController.viewControllers indexOfObject:target] + 1]]; + } + + return super.tabBarItem; +} + +- (UITab *)tab API_AVAILABLE(ios(18.0)) +{ + if([self.parentViewController isKindOfClass:UINavigationController.class]) + { + return self.parentViewController.tab; + } + + return super.tab; +} + +- (NSUInteger)tabIndexInAncestorTabBarController +{ + if(@available(iOS 18, *)) + { + return [self.tabBarController.tabs indexOfObject:self.tab]; + } + else + { + return [self.tabBarController.viewControllers indexOfObject:self.navigationController ?: self]; + } +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [self updateNavigationBarTitlePositionForTraitCollection:self.traitCollection]; + + if(self.colorSeedString == nil) + { + if(self.splitViewController != nil) + { + UIViewController* indexTarget = self.tabBarController ?: self.navigationController ?: self; + NSInteger idx = 1 - [self.splitViewController.viewControllers indexOfObject:indexTarget]; + + self.colorSeedString = [NSString stringWithFormat:@"split_%@_%@%@ccolors", NSStringFromClass(self.splitViewController.class), @(idx), @(idx)]; + } + else if(self.tabBarController != nil) + { + NSUInteger tabIdx = self.tabIndexInAncestorTabBarController; + self.colorSeedString = [NSString stringWithFormat:@"tab_%@", @(tabIdx)]; + } + else + { + self.colorSeedString = @"nil"; + } + self.colorSeedCount = 0; + } + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingDisableDemoSceneColors] == NO) + { + NSString* seed = [NSString stringWithFormat:@"%@%@", self.colorSeedString, self.colorSeedCount == 0 ? @"" : [NSString stringWithFormat:@"%@", @(self.colorSeedCount)]]; + self.view.backgroundColor = LNSeedAdaptiveColor(seed); + } + else + { + self.view.backgroundColor = UIColor.systemBackgroundColor; + } + + [self updateHideTabBarButtonHiddenStateForTraitCollection:self.traitCollection]; + +// UIViewController* settings = [self.storyboard instantiateViewControllerWithIdentifier:@"Settings"]; +// [self addChildViewController:settings]; +// [self.view insertSubview:settings.view atIndex:0]; +// settings.view.frame = self.view.bounds; +// [settings didMoveToParentViewController:self]; +} + +- (void)updateNavigationBarTitlePositionForTraitCollection:(UITraitCollection*)traitCollection +{ + if(@available(iOS 18.0, *)) + { + if(self.tabBarController == nil || UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPad || traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) + { + _hideTabBarButton.image = [UIImage systemImageNamed:@"dock.rectangle"]; + self.navigationItem.backButtonDisplayMode = UINavigationItemBackButtonDisplayModeGeneric; + self.navigationItem.style = UINavigationItemStyleNavigator; + } + else + { + _hideTabBarButton.image = [UIImage _systemImageNamed:@"rectangle.line.horizontal.inset.top"]; + self.navigationItem.backButtonDisplayMode = UINavigationItemBackButtonDisplayModeMinimal; + self.navigationItem.style = UINavigationItemStyleEditor; + } + } +} + +- (void)viewSafeAreaInsetsDidChange +{ + [super viewSafeAreaInsetsDidChange]; +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection +{ + [super traitCollectionDidChange:previousTraitCollection]; + + [self updateBottomDockingViewEffectForBarPresentation]; +} + +- (void)viewIsAppearing:(BOOL)animated +{ + [super viewIsAppearing:animated]; + + [self updateBottomDockingViewEffectForBarPresentation]; + + //Ugly hack to fix tab bar tint color. + self.tabBarController.view.tintColor = self.view.tintColor; + //Ugly hack to fix split view controller tint color. + self.splitViewController.view.tintColor = self.view.tintColor; + //Ugly hack to fix navigation view controller tint color. + self.navigationController.view.tintColor = self.view.tintColor; + + _galleryButton.titleLabel.adjustsFontForContentSizeCategory = YES; + _nextButton.titleLabel.adjustsFontForContentSizeCategory = YES; + + _galleryButton.hidden = [self.parentViewController isKindOfClass:[UINavigationController class]]; + _nextButton.hidden = self.navigationController == nil || self.splitViewController != nil; + + if(self.tabBarController == nil || self.navigationController.topViewController == self.navigationController.viewControllers.firstObject) + { + [self _presentBar:nil animated:NO]; + } +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; +} + +- (void)updateHideTabBarButtonHiddenStateForTraitCollection:(UITraitCollection*)traitCollection; +{ + if(@available(iOS 18.0, *)) + { + if(traitCollection == nil) + { + traitCollection = self.traitCollection; + } + + if(self.tabBarController != nil) + { + [self.navigationItem setHidesBackButton:self.tabBarController.sidebar.isHidden == NO]; + } + + BOOL isFirst = [self.navigationController.viewControllers indexOfObject:self] == 0; + BOOL isTNil = self.tabBarController == nil; + BOOL isNNil = self.navigationController == nil; + BOOL canHaveSidebar = UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad && traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular; + BOOL isSidebarHidden = self.tabBarController.sidebar.isHidden; + + _hideTabBarButton.hidden = isFirst == NO || isNNil || (!isTNil && canHaveSidebar && isSidebarHidden == NO); + } + else + { + if(@available(iOS 16.0, *)) + { + _hideTabBarButton.hidden = self.navigationController == nil || self.tabBarController != nil; + } + else + { + _hideTabBarButton.enabled = self.navigationController == nil || self.tabBarController != nil; + } + } +} + +- (void)viewWillLayoutSubviews +{ + [super viewWillLayoutSubviews]; + + if(@available(iOS 18.0, *)) + { + if(self.tabBarController != nil) + { + [self updateHideTabBarButtonHiddenStateForTraitCollection:self.traitCollection]; + } + } +} + +- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator +{ + [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; + + [coordinator animateAlongsideTransition:^(id _Nonnull context) { + [self updateNavigationBarTitlePositionForTraitCollection:newCollection]; + } completion:nil]; +} + +- (void)dealloc +{ + +} + +- (IBAction)_changeBarStyle:(id)sender +{ + UIUserInterfaceStyle currentStyle = self.navigationController.traitCollection.userInterfaceStyle; + self.navigationController.overrideUserInterfaceStyle = currentStyle == UIUserInterfaceStyleLight ? UIUserInterfaceStyleDark : UIUserInterfaceStyleLight; + self.navigationController.toolbar.tintColor = LNRandomSystemColor(); + [self.navigationController.toolbar.items enumerateObjectsUsingBlock:^(UIBarButtonItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + obj.tintColor = self.navigationController.toolbar.tintColor; + }]; + self.navigationController.navigationBar.tintColor = self.navigationController.toolbar.tintColor; +#if LNPOPUP + [self.navigationController setNeedsPopupBarAppearanceUpdate]; +#endif +} + +- (void)updateBottomDockingViewEffectForBarPresentation +{ + UINavigationBarAppearance* nba = nil; + + BOOL disableScrollEdgeAppearance = [NSUserDefaults.settingDefaults boolForKey:PopupSettingDisableScrollEdgeAppearance]; + if(disableScrollEdgeAppearance) + { + nba = [UINavigationBarAppearance new]; + [nba configureWithDefaultBackground]; + } + +#if LNPOPUP + LNPopupBarStyle popupBarStyle = [[NSUserDefaults.settingDefaults objectForKey:PopupSettingBarStyle] unsignedIntegerValue]; + if(popupBarStyle == LNPopupBarStyleFloating || (popupBarStyle == LNPopupBarStyleDefault && NSProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 17)) +#endif + { + UIBlurEffectStyle style; + if(NSProcessInfo.processInfo.isMacCatalystApp || NSProcessInfo.processInfo.isiOSAppOnMac) + { + style = UIBlurEffectStyleSystemThickMaterial; + } + else + { + style = UIBlurEffectStyleSystemThinMaterial; + } + + UIBlurEffect* effect = [UIBlurEffect effectWithStyle:style]; + +#if LNPOPUP + nba.backgroundEffect = effect; + +#endif + UITabBarAppearance* tba = [UITabBarAppearance new]; + [tba configureWithDefaultBackground]; + tba.backgroundEffect = effect; + self.tabBarController.tabBar.standardAppearance = tba; + + UIToolbarAppearance* ta = [UIToolbarAppearance new]; + [ta configureWithDefaultBackground]; + ta.backgroundEffect = effect; + self.navigationController.toolbar.standardAppearance = ta; + } + + self.navigationController.navigationBar.scrollEdgeAppearance = nba; + self.navigationController.navigationBar.compactScrollEdgeAppearance = nba; + + UITabBarAppearance* tba = nil; + + if(disableScrollEdgeAppearance) + { + tba = [[UITabBarAppearance alloc] initWithBarAppearance:nba]; + } + self.tabBarController.tabBar.scrollEdgeAppearance = tba; + + UIToolbarAppearance* ta = nil; + + if(disableScrollEdgeAppearance) + { + ta = [[UIToolbarAppearance alloc] initWithBarAppearance:nba]; + } + self.navigationController.toolbar.scrollEdgeAppearance = ta; + self.navigationController.toolbar.compactScrollEdgeAppearance = ta; +} + +- (UIViewController*)_targetVCForPopup +{ + void (^block)(NSString*) = ^ (NSString* title) { + self->_hideTabBarButton.enabled = NO; + if(@available(iOS 16.0, *)) + { + self->_hideTabBarButton.hidden = YES; + } + self->_showPopupBarButton.hidden = YES; + self->_hidePopupBarButton.hidden = YES; + [self.navigationController setToolbarHidden:YES animated:NO]; + + if(@available(iOS 17.0, *)) + { + UIContentUnavailableConfiguration* config = [UIContentUnavailableConfiguration emptyConfiguration]; + config.text = title; + [self setContentUnavailableConfiguration:config]; + } + }; + + if([self.splitViewController isKindOfClass:LNSplitViewControllerPrimaryPopup.class] && self.navigationController != [self.splitViewController viewControllerForColumn:UISplitViewControllerColumnPrimary]) + { + self.view.backgroundColor = UIColor.systemBackgroundColor; + block(NSLocalizedString(@"Secondary", @"")); + return nil; + } + + NSMutableArray* vcs = @[self].mutableCopy; + if(self.navigationController) + { + [vcs addObject:self.navigationController]; + } + if([self.splitViewController isKindOfClass:LNSplitViewControllerSecondaryPopup.class] && [vcs containsObject:[self.splitViewController viewControllerForColumn:UISplitViewControllerColumnPrimary]]) + { + self.view.backgroundColor = UIColor.secondarySystemBackgroundColor; + block(NSLocalizedString(@"Sidebar", @"")); + + return nil; + } + + if([self.splitViewController isKindOfClass:LNSplitViewControllerGlobalPopup.class]) + { + return self.splitViewController; + } + + UIViewController* targetVC = self.tabBarController; + + if(targetVC == nil) + { + targetVC = self.navigationController; + + if(targetVC == nil) + { + targetVC = self; + } + } + + return targetVC; +} + +- (IBAction)_presentBar:(id)sender +{ + [self _presentBar:sender animated:YES]; +} + +- (void)_presentBar:(id)sender animated:(BOOL)animated; +{ +#if LNPOPUP + if(_alreadyPresentedAutomatically == YES && sender == nil) + { + return; + } + + if(sender == nil) + { + _alreadyPresentedAutomatically = YES; + } + + UIViewController* targetVC = [self _targetVCForPopup]; + + if(targetVC == nil) + { + return; + } + + if(targetVC.popupContentViewController != nil) + { + return; + } + + if(targetVC == self.navigationController && self.navigationController.viewControllers.count > 1 && self.splitViewController == nil && sender == nil) + { + return; + } + + UIViewController* demoVC; + + switch([NSUserDefaults.settingDefaults integerForKey:PopupSettingUseScrollingPopupContent]) + { + case 10: + case 11: + demoVC = [self.storyboard instantiateViewControllerWithIdentifier:@"ScrollingColors"]; + break; + + case 20: + demoVC = [self.storyboard instantiateViewControllerWithIdentifier:@"VerticalPagedScrollingColors"]; + break; + case 21: + demoVC = [self.storyboard instantiateViewControllerWithIdentifier:@"HorizontalPagedScrollingColors"]; + break; + case 22: + demoVC = [self.storyboard instantiateViewControllerWithIdentifier:@"VerticalGroupedPagedScrollingColors"]; + break; + case 23: + demoVC = [self.storyboard instantiateViewControllerWithIdentifier:@"HorizontalGroupedPagedScrollingColors"]; + break; + + case 100: + demoVC = [self.storyboard instantiateViewControllerWithIdentifier:@"ScrollingMap"]; + break; + default: + demoVC = [DemoPopupContentViewController new]; + break; + } + + LNPopupCloseButtonStyle closeButtonStyle = [[NSUserDefaults.settingDefaults objectForKey:PopupSettingCloseButtonStyle] unsignedIntegerValue]; + + targetVC.popupContentView.popupCloseButton.accessibilityLabel = NSLocalizedString(@"Custom popup button accessibility label", @""); + targetVC.popupContentView.popupCloseButton.accessibilityHint = NSLocalizedString(@"Custom popup button accessibility hint", @""); + + targetVC.popupBar.progressViewStyle = [[NSUserDefaults.settingDefaults objectForKey:PopupSettingProgressViewStyle] unsignedIntegerValue]; + targetVC.popupBar.barStyle = [[NSUserDefaults.settingDefaults objectForKey:PopupSettingBarStyle] unsignedIntegerValue]; + + targetVC.popupInteractionStyle = [[NSUserDefaults.settingDefaults objectForKey:PopupSettingInteractionStyle] unsignedIntegerValue]; + + if(targetVC.effectivePopupInteractionStyle == LNPopupInteractionStyleScroll && [NSUserDefaults.settingDefaults integerForKey:PopupSettingUseScrollingPopupContent] == 0) + { + targetVC.popupInteractionStyle = LNPopupInteractionStyleSnap; + } + + targetVC.popupContentView.popupCloseButtonStyle = closeButtonStyle; + + targetVC.allowPopupHapticFeedbackGeneration = [NSUserDefaults.settingDefaults boolForKey:PopupSettingHapticFeedbackEnabled]; + + targetVC.popupBar.limitFloatingContentWidth = [NSUserDefaults.settingDefaults boolForKey:PopupSettingLimitFloatingWidth]; + + NSNumber* effectOverride = [NSUserDefaults.settingDefaults objectForKey:PopupSettingVisualEffectViewBlurEffect]; + if(effectOverride != nil && effectOverride.unsignedIntValue != 0xffff) + { + if(targetVC.popupBar.effectiveBarStyle == LNPopupBarStyleFloating) + { + targetVC.popupBar.standardAppearance.floatingBackgroundEffect = [UIBlurEffect effectWithStyle:effectOverride.unsignedIntegerValue]; + } + else + { + targetVC.popupBar.inheritsAppearanceFromDockingView = NO; + targetVC.popupBar.standardAppearance.backgroundEffect = [UIBlurEffect effectWithStyle:effectOverride.unsignedIntegerValue]; + } + } + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingEnableCustomizations]) + { + LNPopupBarAppearance* appearance = [LNPopupBarAppearance new]; + + NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + paragraphStyle.alignment = NSTextAlignmentRight; + paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail; + + appearance.titleTextAttributes = @{NSParagraphStyleAttributeName: paragraphStyle, NSFontAttributeName: [[UIFontMetrics metricsForTextStyle:UIFontTextStyleHeadline] scaledFontForFont:[UIFont fontWithName:@"Chalkduster" size:14]], NSForegroundColorAttributeName: UIColor.yellowColor}; + appearance.subtitleTextAttributes = @{NSParagraphStyleAttributeName: paragraphStyle, NSFontAttributeName: [[UIFontMetrics metricsForTextStyle:UIFontTextStyleSubheadline] scaledFontForFont:[UIFont fontWithName:@"Chalkduster" size:12]], NSForegroundColorAttributeName: UIColor.greenColor}; + + appearance.floatingBarBackgroundShadow.shadowColor = UIColor.redColor; + appearance.imageShadow.shadowColor = UIColor.yellowColor; + + if(targetVC.popupBar.barStyle == LNPopupBarStyleFloating || (targetVC.popupBar.barStyle == LNPopupBarStyleDefault && NSProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 17)) + { + appearance.floatingBackgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + } + else + { + + appearance.backgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + targetVC.popupBar.inheritsAppearanceFromDockingView = NO; + } + + targetVC.popupBar.tintColor = UIColor.yellowColor; + targetVC.popupBar.standardAppearance = appearance; + } + + targetVC.popupBar.standardAppearance.marqueeScrollEnabled = [NSUserDefaults.settingDefaults boolForKey:PopupSettingMarqueeEnabled]; + targetVC.popupBar.standardAppearance.coordinateMarqueeScroll = [NSUserDefaults.settingDefaults boolForKey:PopupSettingMarqueeCoordinationEnabled]; + + targetVC.shouldExtendPopupBarUnderSafeArea = [NSUserDefaults.settingDefaults boolForKey:PopupSettingExtendBar]; + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingContextMenuEnabled]) + { + [targetVC.popupBar addInteraction:[[LNPopupDemoContextMenuInteraction alloc] initWithTitle:YES]]; + } + + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingCustomBarEverywhereEnabled]) + { + targetVC.shouldExtendPopupBarUnderSafeArea = NO; + targetVC.popupBar.inheritsAppearanceFromDockingView = NO; + targetVC.popupBar.customBarViewController = [ManualLayoutCustomBarViewController new]; + [targetVC.popupBar.standardAppearance configureWithTransparentBackground]; + } + + targetVC.popupPresentationDelegate = self; + [targetVC presentPopupBarWithContentViewController:demoVC animated:animated completion:nil]; +#endif +} + +- (IBAction)_dismissBar:(id)sender +{ +#if LNPOPUP + __kindof UIViewController* targetVC = [self _targetVCForPopup]; + [targetVC dismissPopupBarAnimated:YES completion:nil]; +#endif +} + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender +{ + segue.destinationViewController.hidesBottomBarWhenPushed = +#if LNPOPUP + [NSUserDefaults.settingDefaults boolForKey:PopupSettingHidesBottomBarWhenPushed]; +#else + YES; +#endif + if([segue.destinationViewController isKindOfClass:DemoViewController.class]) + { + [(DemoViewController*)segue.destinationViewController setColorSeedString:self.colorSeedString]; + [(DemoViewController*)segue.destinationViewController setColorSeedCount:self.colorSeedCount + 1]; + } +} + +- (IBAction)_hideBottomBar:(id)sender +{ + if(self.tabBarController != nil) + { + if(@available(iOS 18.0, *)) + { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 180000 + [self.tabBarController setTabBarHidden:!self.tabBarController.isTabBarHidden animated:YES]; +#endif + } + } + else if(self.navigationController != nil) + { + [self.navigationController setToolbarHidden:!self.navigationController.isToolbarHidden animated:YES]; + } +} + +#pragma mark LNPopupPresentationDelegate + +- (void)popupPresentationControllerWillPresentPopupBar:(UIViewController*)popupPresentationController animated:(BOOL)animated +{ + +} + +- (void)popupPresentationControllerDidPresentPopupBar:(UIViewController*)popupPresentationController animated:(BOOL)animated +{ + +} + +- (void)popupPresentationControllerWillDismissPopupBar:(UIViewController*)popupPresentationController animated:(BOOL)animated +{ + +} + +- (void)popupPresentationControllerDidDismissPopupBar:(UIViewController*)popupPresentationController animated:(BOOL)animated +{ + +} + +- (void)popupPresentationController:(UIViewController *)popupPresentationController willOpenPopupWithContentController:(UIViewController *)popupContentController animated:(BOOL)animated +{ + +} + +- (void)popupPresentationController:(UIViewController *)popupPresentationController didOpenPopupWithContentController:(UIViewController *)popupContentController animated:(BOOL)animated +{ + +} + +- (void)popupPresentationController:(UIViewController *)popupPresentationController willClosePopupWithContentController:(UIViewController *)popupContentController animated:(BOOL)animated +{ + +} + +- (void)popupPresentationController:(UIViewController *)popupPresentationController didClosePopupWithContentController:(UIViewController *)popupContentController animated:(BOOL)animated +{ + +} + +@end + +@interface PassthroughNavigationController : UINavigationController @end +@implementation PassthroughNavigationController + +- (UITabBarItem *)tabBarItem +{ + return self.viewControllers.firstObject.tabBarItem; +} + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/IntroWebViewController.h b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/IntroWebViewController.h new file mode 100644 index 0000000..bc5f0eb --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/IntroWebViewController.h @@ -0,0 +1,17 @@ +// +// IntroWebViewController.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2020-10-28. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface IntroWebViewController : UIViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/IntroWebViewController.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/IntroWebViewController.m new file mode 100644 index 0000000..8e013d4 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/IntroWebViewController.m @@ -0,0 +1,100 @@ +// +// IntroWebViewController.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2020-10-28. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "IntroWebViewController.h" +#import "SafeSystemImages.h" +#import "LNPopupControllerExample-Bridging-Header.h" +@import WebKit; +@import LNPopupController; + +@interface IntroWebViewController () +{ + WKWebView* _webView; + UIView* _topColorView; +} + +@end + +@implementation IntroWebViewController + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return UIStatusBarStyleLightContent; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + _webView = [WKWebView new]; + [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://github.com/LeoNatan/LNPopupController"]]]; + _webView.translatesAutoresizingMaskIntoConstraints = NO; + _webView.allowsBackForwardNavigationGestures = YES; +// _webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + _webView.scrollView.automaticallyAdjustsScrollIndicatorInsets = NO; + [self.view addSubview:_webView]; + +// UIBlurEffectStyle style = UIBlurEffectStyleSystemThinMaterial; +// _effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:style]]; + _topColorView = [UIView new]; + _topColorView.backgroundColor = [UIColor colorWithRed:0.12 green:0.14 blue:0.15 alpha:1.0]; + _topColorView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:_topColorView]; + + [NSLayoutConstraint activateConstraints:@[ + [self.view.topAnchor constraintEqualToAnchor:_webView.topAnchor], + [self.view.bottomAnchor constraintEqualToAnchor:_webView.bottomAnchor], + [self.view.leadingAnchor constraintEqualToAnchor:_webView.leadingAnchor], + [self.view.trailingAnchor constraintEqualToAnchor:_webView.trailingAnchor], + + [self.view.topAnchor constraintEqualToAnchor:_topColorView.topAnchor], + [self.view.safeAreaLayoutGuide.topAnchor constraintEqualToAnchor:_topColorView.bottomAnchor], + [self.view.leadingAnchor constraintEqualToAnchor:_topColorView.leadingAnchor], + [self.view.trailingAnchor constraintEqualToAnchor:_topColorView.trailingAnchor], + ]]; + + self.popupItem.image = [UIImage imageNamed:@"AppIconPopupBar"]; + self.popupItem.barButtonItems = @[ + [[UIBarButtonItem alloc] initWithImage:LNSystemImage(@"suit.heart.fill", LNSystemImageScaleNormal) style:UIBarButtonItemStylePlain target:self action:@selector(_navigate:)], + ]; + + NSString* title = NSLocalizedString(@"Welcome to LNPopupController!", @""); + + NSMutableAttributedString* attribTitle = [[NSMutableAttributedString alloc] initWithString:title]; + [attribTitle addAttributes:@{ + NSFontAttributeName: [[UIFontMetrics metricsForTextStyle:UIFontTextStyleBody] scaledFontForFont:[UIFont systemFontOfSize:15 weight:UIFontWeightMedium]], + } range:NSMakeRange(0, attribTitle.length)]; + [attribTitle addAttributes: @{ + NSFontAttributeName: [[UIFontMetrics metricsForTextStyle:UIFontTextStyleHeadline] scaledFontForFont:[UIFont systemFontOfSize:16 weight:UIFontWeightHeavy]], + } range:[title rangeOfString:NSLocalizedString(@"LNPopupController", @"")]]; + + self.popupItem.attributedTitle = attribTitle; + + [_webView addObserver:self forKeyPath:@"themeColor" options:NSKeyValueObservingOptionNew context:NULL]; + [_webView addObserver:self forKeyPath:@"underPageBackgroundColor" options:NSKeyValueObservingOptionNew context:NULL]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ +// _effectView.effect = nil; + _topColorView.backgroundColor = _webView.themeColor; +} + +- (IBAction)_navigate:(id)sender +{ + [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://github.com/LeoNatan/LNPopupController"] options:@{} completionHandler:nil]; +} + +- (void)viewSafeAreaInsetsDidChange +{ + [super viewSafeAreaInsetsDidChange]; + + _webView.scrollView.scrollIndicatorInsets = self.view.safeAreaInsets; +} + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupControllerExampleSupport.h b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupControllerExampleSupport.h new file mode 100644 index 0000000..8eeef89 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupControllerExampleSupport.h @@ -0,0 +1,13 @@ +// +// LNPopupControllerExampleSupport.h +// LNPopupControllerExampleSupport +// +// Created by Léo Natan on 2021-08-31. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +@import UIKit; + +NS_ASSUME_NONNULL_BEGIN + +NS_ASSUME_NONNULL_END diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupControllerExampleSupport.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupControllerExampleSupport.m new file mode 100644 index 0000000..b35404f --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupControllerExampleSupport.m @@ -0,0 +1,177 @@ +// +// LNPopupControllerExampleSupport.m +// LNPopupControllerExampleSupport +// +// Created by Léo Natan on 2021-08-31. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "LNPopupControllerExampleSupport.h" +#import "SettingKeys.h" + +@interface DemoGalleryControllerTableView : UITableView @end +@implementation DemoGalleryControllerTableView + +- (BOOL)canBecomeFocused +{ + return NO; +} + +@end + +@interface DemoTabBarController : UITabBarController @end + +@implementation DemoTabBarController +{ + NSMutableArray* _tabs API_AVAILABLE(ios(18.0)); + NSMutableArray* _sidebarTabs API_AVAILABLE(ios(18.0)); +} + +- (void)awakeFromNib +{ + if(@available(iOS 18.0, *)) + { + _tabs = [NSMutableArray new]; + + NSUInteger idx = 0; + for(UIViewController* vc in self.viewControllers) + { + NSString* title = vc.tabBarItem.title; + if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + title = [NSString stringWithFormat:@"%@ %@", title, @(idx + 1)]; + } + + UITab* tab = [[UITab alloc] initWithTitle:title image:[UIImage systemImageNamed:[NSString stringWithFormat:@"%@.square", @(idx + 1)]] identifier:[NSString stringWithFormat:@"%@_%@", vc.tabBarItem.title, @(idx)] viewControllerProvider:^UIViewController * _Nonnull(__kindof UITab * _Nonnull tab) { + return vc; + }]; + [_tabs addObject:tab]; + idx++; + } + + _sidebarTabs = [NSMutableArray new]; + if([NSUserDefaults.settingDefaults boolForKey:PopupSettingTabBarHasSidebar]) + { + if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + BOOL wantsNav = [_tabs.firstObject.viewController isKindOfClass:UINavigationController.class]; + + for(NSUInteger jdx = 0; jdx <= 3; jdx++) + { + UIViewController* vc; + if(wantsNav) + { + vc = [self.storyboard instantiateViewControllerWithIdentifier:@"navDemoView"]; + } + else + { + vc = [self.storyboard instantiateViewControllerWithIdentifier:@"demoVC"]; + } + + UITab* sidebarOnly = [[UITab alloc] initWithTitle:[NSString stringWithFormat:@"Sidebar Tab %@", @(idx + 1)] image:[UIImage systemImageNamed:[NSString stringWithFormat:@"%@.square", @(idx + 1)]] identifier:[NSString stringWithFormat:@"sidebar_%@", @(idx)] viewControllerProvider:^UIViewController * _Nonnull(__kindof UITab * _Nonnull tab) { + return vc; + }]; + sidebarOnly.preferredPlacement = UITabPlacementSidebarOnly; + [_sidebarTabs addObject:sidebarOnly]; + idx++; + } + } + } + + self.viewControllers = nil; + } + + [super awakeFromNib]; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + if(@available(iOS 18.0, *)) + { + [self updateTabsForTraitCollection:self.traitCollection]; + } +} + +- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator +{ + [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; + + [coordinator animateAlongsideTransition:^(id _Nonnull context) { + if(@available(iOS 18.0, *)) + { + [self updateTabsForTraitCollection:newCollection]; + } + } completion:nil]; +} + +- (void)updateTabsForTraitCollection:(UITraitCollection*)collection API_AVAILABLE(ios(18.0)) +{ + if(collection.userInterfaceIdiom == UIUserInterfaceIdiomPad && collection.horizontalSizeClass == UIUserInterfaceSizeClassRegular && _sidebarTabs.count > 0 && self.splitViewController == nil) + { + self.tabs = [_tabs arrayByAddingObjectsFromArray:_sidebarTabs]; + self.compactTabIdentifiers = [_tabs valueForKey:@"identifier"]; + + self.mode = UITabBarControllerModeTabSidebar; + self.sidebar.preferredLayout = UITabBarControllerSidebarLayoutAutomatic; + self.sidebar.hidden = YES; + self.customizableViewControllers = @[]; + } + else + { + self.tabs = _tabs; + self.mode = UITabBarControllerModeTabBar; + } +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; +} + +@end + +@interface DemoTabBar : UITabBar @end +@implementation DemoTabBar + +- (void)willMoveToSuperview:(UIView *)newSuperview +{ + [super willMoveToSuperview:newSuperview]; +} + +- (void)setFrame:(CGRect)frame +{ +// NSLog(@"🤦â€�♂ï¸� frame: %@ safe area: %@", @(frame), [self valueForKey:@"safeAreaInsets"]); + + [super setFrame:frame]; +} + +@end + +@interface DemoToolbar : UIToolbar @end +@implementation DemoToolbar + +- (void)setFrame:(CGRect)frame +{ +// NSLog(@"🤦â€�♂ï¸� frame: %@ safe area: %@", @(frame), [self valueForKey:@"safeAreaInsets"]); + + [super setFrame:frame]; +} + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupDemoContextMenuInteraction.h b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupDemoContextMenuInteraction.h new file mode 100644 index 0000000..38640b3 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupDemoContextMenuInteraction.h @@ -0,0 +1,21 @@ +// +// LNPopupDemoContextMenuInteraction.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2021-12-17. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface LNPopupDemoContextMenuInteraction : UIContextMenuInteraction + +- (instancetype)init; +- (instancetype)initWithTitle:(BOOL)title; ++ (instancetype)new; + +@end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupDemoContextMenuInteraction.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupDemoContextMenuInteraction.m new file mode 100644 index 0000000..0f42f21 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNPopupDemoContextMenuInteraction.m @@ -0,0 +1,72 @@ +// +// LNPopupDemoContextMenuInteraction.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2021-12-17. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "LNPopupDemoContextMenuInteraction.h" +#import "IntroWebViewController.h" + +@interface LNPopupDemoContextMenuInteraction () + +@end + +@implementation LNPopupDemoContextMenuInteraction +{ + BOOL _includeTitle; +} + +- (instancetype)init +{ + return [self initWithTitle:NO]; +} + +- (instancetype)initWithTitle:(BOOL)title +{ + self = [super initWithDelegate:self]; + + if(self) + { + _includeTitle = title; + } + + return self; +} + ++ (instancetype)new +{ + return [[self alloc] init]; +} + +#pragma mark UIContextMenuInteractionDelegate + +- (nullable UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location +{ + return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu * _Nullable(NSArray * _Nonnull suggestedActions) { + return [UIMenu menuWithTitle: self->_includeTitle ? @"LNPopupController" : @"" children:@[ + [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[ + [UIAction actionWithTitle:NSLocalizedString(@"Visit GitHub Page", @"") image:[UIImage systemImageNamed:@"safari"] identifier:nil handler:^(__kindof UIAction * _Nonnull action) + { + [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://github.com/LeoNatan/LNPopupController"] options:@{} completionHandler:nil]; + }], + [UIAction actionWithTitle:NSLocalizedString(@"Report an Issue…", @"") image:[UIImage systemImageNamed:@"ant.fill"] identifier:nil handler:^(__kindof UIAction * _Nonnull action) + { + [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://github.com/LeoNatan/LNPopupController/issues/new/choose"] options:@{} completionHandler:nil]; + }] + ]], + [UIAction actionWithTitle:NSLocalizedString(@"Share…", @"") image:[UIImage systemImageNamed:@"square.and.arrow.up"] identifier:nil handler:^(__kindof UIAction * _Nonnull action) + { + UIView* popupBar = [action valueForKeyPath:@"sender.view"]; + UIViewController* presentingController = [popupBar valueForKeyPath:@"viewControllerForAncestor"]; + UIActivityViewController* avc = [[UIActivityViewController alloc] initWithActivityItems:@[[NSURL URLWithString:@"https://github.com/LeoNatan/LNPopupController"]] applicationActivities:nil]; + avc.modalPresentationStyle = UIModalPresentationFormSheet; + avc.popoverPresentationController.sourceView = popupBar; + [presentingController presentViewController:avc animated:YES completion:nil]; + }], + ]]; + }]; +} + +@end diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.h b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.h new file mode 100644 index 0000000..13ce71b --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.h @@ -0,0 +1,21 @@ +// +// SplitViewController.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2023-10-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +@import UIKit; + +NS_ASSUME_NONNULL_BEGIN + +@class LNSplitViewController; + +@interface LNSplitViewController : UISplitViewController @end + +@interface LNSplitViewControllerPrimaryPopup : LNSplitViewController @end +@interface LNSplitViewControllerSecondaryPopup : LNSplitViewController @end +@interface LNSplitViewControllerGlobalPopup : LNSplitViewController @end + +NS_ASSUME_NONNULL_END diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.m b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.m new file mode 100644 index 0000000..df49c76 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/LNSplitViewController.m @@ -0,0 +1,44 @@ +// +// LNSplitViewController.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2023-10-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#import "LNSplitViewController.h" + +@implementation LNSplitViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + if([self isKindOfClass:LNSplitViewControllerSecondaryPopup.class] == NO) + { + self.minimumPrimaryColumnWidth = 400; + self.maximumPrimaryColumnWidth = 400; + + if(self.style == UISplitViewControllerStyleTripleColumn) + { + self.minimumSupplementaryColumnWidth = 400; + self.maximumSupplementaryColumnWidth = 400; + } + } +} + +- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator +{ + [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; + + if(newCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) + { + [self.presentingViewController dismissViewControllerAnimated:NO completion:nil]; + } +} + +@end + +@implementation LNSplitViewControllerPrimaryPopup @end +@implementation LNSplitViewControllerSecondaryPopup @end +@implementation LNSplitViewControllerGlobalPopup @end diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/PageCardViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/PageCardViewController.swift new file mode 100644 index 0000000..f9f1808 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/PageCardViewController.swift @@ -0,0 +1,43 @@ +// +// PageCardViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2024-09-27. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit + +class PageCardViewController: UIViewController { + @IBOutlet var cardView: UIView! + @IBOutlet var indexLabel: UILabel! + public +var prefix: String? = nil { + didSet { + if isViewLoaded { + indexLabel.text = "\(prefix == nil ? "" : prefix!)\(index)" + } + } + } + public +var index: Int = -1 { + didSet { + if isViewLoaded { + indexLabel.text = "\(prefix == nil ? "" : prefix!)\(index)" + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + cardView.layer.cornerCurve = .continuous + cardView.layer.cornerRadius = 40 + + indexLabel.text = "\(prefix == nil ? "" : prefix!)\(index)" + } + + override func viewSafeAreaInsetsDidChange() { + super.viewSafeAreaInsetsDidChange() + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingColorsPageViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingColorsPageViewController.swift new file mode 100644 index 0000000..89d4df3 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingColorsPageViewController.swift @@ -0,0 +1,122 @@ +// +// ScrollingColorsPageViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2024-09-27. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit +import LNPopupController + +protocol Indexable { + var index: Int { get set } +} + +class _ScrollingColorsPageViewController: UIPageViewController, UIPageViewControllerDataSource { + override func viewDidLoad() { + super.viewDidLoad() +#if LNPOPUP + let useCompact = UserDefaults.settings.integer(forKey: .barStyle) == LNPopupBar.Style.compact.rawValue + + let gridBarButtonItem = UIBarButtonItem() + gridBarButtonItem.image = LNSystemImage("rectangle.portrait.fill", scale: useCompact ? .compact : .normal) + popupItem.barButtonItems = [gridBarButtonItem] + + LNApplyTitleWithSettings(to: self) +#endif + + dataSource = self + + setViewControllers([viewController(at: 0)], direction: .forward, animated: false) + } + + var isVertical: Bool { + self.navigationOrientation == .vertical + } + + dynamic func viewController(at index: Int) -> T { + fatalError() + } + + dynamic var totalCount: Int { + fatalError() + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { + let viewController = viewController as! T + + if viewController.index == 0 { + return nil + } + + return self.viewController(at: viewController.index - 1) + } + + func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { + let viewController = viewController as! T + + if viewController.index == totalCount - 1 { + return nil + } + + return self.viewController(at: viewController.index + 1) + } + + override func viewSafeAreaInsetsDidChange() { + super.viewSafeAreaInsetsDidChange() + } +} + +extension PageCardViewController: Indexable {} + +class ScrollingColorsPageViewController: _ScrollingColorsPageViewController, Indexable { + var colors: [UIColor] = [] + var index: Int = -1 + var prefix: String? = nil { + didSet { + (viewControllers as! [PageCardViewController]).forEach { $0.prefix = prefix } + } + } + + override var totalCount: Int { + colors.count + } + + override func viewDidLoad() { + for _ in 0..<30 { + colors.append(LNRandomSystemColor()) + } + + super.viewDidLoad() + } + + override func viewController(at index: Int) -> PageCardViewController { + let rv = self.storyboard!.instantiateViewController(withIdentifier: "PagedCard") as! PageCardViewController + rv.index = index + rv.prefix = prefix + rv.loadViewIfNeeded() + rv.cardView.backgroundColor = colors[index] + return rv + } +} + +class ScrollingGroupedColorsPageViewController: _ScrollingColorsPageViewController { + override var totalCount: Int { + return 10 + } + + override func viewController(at index: Int) -> ScrollingColorsPageViewController { + let identifier: String + if isVertical { + identifier = "HorizontalPagedScrollingColors" + } else { + identifier = "VerticalPagedScrollingColors" + } + + let rv = self.storyboard!.instantiateViewController(withIdentifier: identifier) as! ScrollingColorsPageViewController + rv.index = index + rv.prefix = "\(index)_" + return rv + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingColorsViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingColorsViewController.swift new file mode 100644 index 0000000..14475e0 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingColorsViewController.swift @@ -0,0 +1,94 @@ +// +// ScrollingColorsViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2024-09-26. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit +import LNPopupController + +class ScrollingColorsViewController: UICollectionViewController { + var colors: [UIColor] = [] + + override func viewDidLoad() { + super.viewDidLoad() + + for _ in 0.. Int { + isVertical ? 1000 : 30 + } + + override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ColorCell", for: indexPath) + cell.contentView.backgroundColor = colors[indexPath.item] + return cell + } + + func createVerticalGridLayout() -> UICollectionViewLayout { + UICollectionViewCompositionalLayout { sectionIdx, environment in + let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0/3), heightDimension: .fractionalHeight(1.0)) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + + let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(1.0/3)) + let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) + + group.interItemSpacing = .fixed(2) + + let section = NSCollectionLayoutSection(group: group) + section.interGroupSpacing = 2 + return section + } + } + + func createHorizontalGridLayout() -> UICollectionViewLayout { + let layout = UICollectionViewCompositionalLayout { sectionIdx, environment in + let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + + let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .fractionalHeight(1.0)) + let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) + + let section = NSCollectionLayoutSection(group: group) + section.interGroupSpacing = 16 + return section + } + + let config = UICollectionViewCompositionalLayoutConfiguration() + config.scrollDirection = .horizontal + config.contentInsetsReference = .none + + layout.configuration = config + + return layout + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingMapViewController.swift b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingMapViewController.swift new file mode 100644 index 0000000..ba0e902 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/TestingScene/ScrollingMapViewController.swift @@ -0,0 +1,25 @@ +// +// ScrollingMapViewController.swift +// LNPopupControllerExample +// +// Created by Léo Natan on 2024-09-27. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +import UIKit + +class ScrollingMapViewController: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + +#if LNPOPUP + let useCompact = UserDefaults.settings.integer(forKey: .barStyle) == LNPopupBar.Style.compact.rawValue + + let gridBarButtonItem = UIBarButtonItem() + gridBarButtonItem.image = LNSystemImage("map", scale: useCompact ? .compact : .normal) + popupItem.barButtonItems = [gridBarButtonItem] + + LNApplyTitleWithSettings(to: self) +#endif + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Utils/RandomColors.h b/LNPopupControllerExample/LNPopupControllerExample/Utils/RandomColors.h new file mode 100644 index 0000000..24de8f6 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Utils/RandomColors.h @@ -0,0 +1,21 @@ +// +// RandomColors.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +@import UIKit; + +extern UIColor* LNRandomSystemColor(void); + +extern UIColor* LNSeedAdaptiveColor(NSString* seed); +extern UIColor* LNSeedAdaptiveInvertedColor(NSString* seed); +extern UIColor* LNRandomAdaptiveColor(void); +extern UIColor* LNRandomAdaptiveInvertedColor(void); + +extern UIColor* LNSeedDarkColor(NSString* seed); +extern UIColor* LNSeedLightColor(NSString* seed); +extern UIColor* LNRandomDarkColor(void); +extern UIColor* LNRandomLightColor(void); diff --git a/LNPopupControllerExample/LNPopupControllerExample/Utils/RandomColors.m b/LNPopupControllerExample/LNPopupControllerExample/Utils/RandomColors.m new file mode 100644 index 0000000..f183ccc --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Utils/RandomColors.m @@ -0,0 +1,134 @@ +// +// RandomColors.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2015-08-23. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +@import UIKit; +#import "RandomColors.h" + +static NSMutableArray* namedSystemColors; +static NSUInteger lastNamedSystemColorIdx = 0; + +__attribute__((constructor)) +static void LNInitializeDemoColors(void) +{ + namedSystemColors = @[ + UIColor.systemRedColor, + UIColor.systemGreenColor, + UIColor.systemBlueColor, + UIColor.systemOrangeColor, + UIColor.systemYellowColor, + UIColor.systemPinkColor, + UIColor.systemPurpleColor, + UIColor.systemTealColor, + UIColor.systemIndigoColor, + UIColor.systemBrownColor, + ].mutableCopy; + if(@available(iOS 15.0, *)) + { + [namedSystemColors addObject:UIColor.systemMintColor]; + [namedSystemColors addObject:UIColor.systemCyanColor]; + } +} + +UIColor* LNRandomSystemColor(void) +{ +// return namedSystemColors[arc4random_uniform((uint32_t)namedSystemColors.count)]; + + NSUInteger rv = lastNamedSystemColorIdx; + lastNamedSystemColorIdx = (lastNamedSystemColorIdx + 1) % namedSystemColors.count; + return namedSystemColors[rv]; +} + +UIColor* _LNSeedDarkColor(long seed) +{ + srand48(seed); + CGFloat hue = drand48(); + CGFloat saturation = 0.5; + CGFloat brightness = 0.3 + 0.1 * drand48(); + return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1]; +} + +UIColor* _LNSeedLightColor(long seed) +{ + srand48(seed); + CGFloat hue = drand48(); + CGFloat saturation = 0.5; + CGFloat brightness = 1.0 - 0.1 * drand48(); + return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1]; +} + +UIColor* _LNSeedAdaptiveColor(long seed) +{ + UIColor* light = _LNSeedLightColor(seed); + UIColor* dark = _LNSeedDarkColor(seed); + return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull collection) { + if(collection.userInterfaceStyle == UIUserInterfaceStyleDark) + { + return dark; + } + else + { + return light; + } + }]; +} + +UIColor* _LNSeedAdaptiveInvertedColor(long seed) +{ + UIColor* light = _LNSeedLightColor(seed); + UIColor* dark = _LNSeedDarkColor(seed); + return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull collection) { + if(collection.userInterfaceStyle == UIUserInterfaceStyleDark) + { + return light; + } + else + { + return dark; + } + }]; +} + +UIColor* LNRandomAdaptiveColor(void) +{ + return _LNSeedAdaptiveColor(arc4random()); +} + +UIColor* LNRandomAdaptiveInvertedColor(void) +{ + return _LNSeedAdaptiveInvertedColor(arc4random()); +} + +UIColor* LNSeedAdaptiveColor(NSString* seed) +{ + return _LNSeedAdaptiveColor(seed.hash); +} + +UIColor* LNSeedAdaptiveInvertedColor(NSString* seed) +{ + return _LNSeedAdaptiveInvertedColor(seed.hash); +} + +UIColor* LNRandomDarkColor(void) +{ + return _LNSeedDarkColor(arc4random()); +} + +UIColor* LNRandomLightColor(void) +{ + return _LNSeedLightColor(arc4random()); +} + +UIColor* LNSeedDarkColor(NSString* seed) +{ + return _LNSeedDarkColor(seed.hash); +} + +UIColor* LNSeedLightColor(NSString* seed) +{ + return _LNSeedLightColor(seed.hash); +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Utils/SafeSystemImages.h b/LNPopupControllerExample/LNPopupControllerExample/Utils/SafeSystemImages.h new file mode 100644 index 0000000..05a4d89 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Utils/SafeSystemImages.h @@ -0,0 +1,24 @@ +// +// SafeSystemImages.h +// LNPopupControllerExample +// +// Created by Léo Natan on 2023-09-02. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +@import UIKit; + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, LNSystemImageScale) { + LNSystemImageScaleCompact, + LNSystemImageScaleNormal, + LNSystemImageScaleLarge, + LNSystemImageScaleLarger +}; + +extern UIImage* LNSystemImage(NSString* named, LNSystemImageScale scale) NS_SWIFT_NAME(LNSystemImage(_:scale:)); +extern UIBarButtonItem* LNSystemBarButtonItem(NSString* named, LNSystemImageScale scale, __nullable id target, __nullable SEL action) NS_SWIFT_NAME(LNSystemBarButtonItem(_:scale:target:action:)); +extern UIBarButtonItem* LNSystemBarButtonItemAction(NSString* named, LNSystemImageScale scale, UIAction* primaryAction) NS_SWIFT_NAME(LNSystemBarButtonItem(_:scale:primaryAction:)); + +NS_ASSUME_NONNULL_END diff --git a/LNPopupControllerExample/LNPopupControllerExample/Utils/SafeSystemImages.m b/LNPopupControllerExample/LNPopupControllerExample/Utils/SafeSystemImages.m new file mode 100644 index 0000000..d8528d2 --- /dev/null +++ b/LNPopupControllerExample/LNPopupControllerExample/Utils/SafeSystemImages.m @@ -0,0 +1,94 @@ +// +// SafeSystemImages.m +// LNPopupControllerExample +// +// Created by Léo Natan on 2023-09-02. +// Copyright © 2015-2025 Léo Natan. All rights reserved. +// + +#include "SafeSystemImages.h" + +UIImage* LNSystemImage(NSString* named, LNSystemImageScale scale) +{ + static NSDictionary* configMap; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + configMap = @{ + @(LNSystemImageScaleCompact): [UIImageSymbolConfiguration configurationWithScale:UIImageSymbolScaleMedium], + @(LNSystemImageScaleNormal): [UIImageSymbolConfiguration configurationWithTextStyle:UIFontTextStyleHeadline scale:UIImageSymbolScaleLarge], + @(LNSystemImageScaleLarge): [UIImageSymbolConfiguration configurationWithTextStyle:UIFontTextStyleTitle3 scale:UIImageSymbolScaleLarge], + @(LNSystemImageScaleLarger): [UIImageSymbolConfiguration configurationWithTextStyle:UIFontTextStyleTitle1 scale:UIImageSymbolScaleLarge], + }; + }); + + UIImageSymbolConfiguration* config = configMap[@(scale)]; + return [UIImage systemImageNamed:named withConfiguration:config]; +} + +CGFloat _LNWidthForScale(LNSystemImageScale scale) +{ + static NSDictionary* widthMap; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + widthMap = @{ + @(LNSystemImageScaleCompact): @(44), + @(LNSystemImageScaleNormal): @(60), + @(LNSystemImageScaleLarge): @(60), + @(LNSystemImageScaleLarger): @(62), + }; + }); + + return [widthMap[@(scale)] doubleValue]; +} + +UIBarButtonItem* LNSystemBarButtonItem(NSString* name, LNSystemImageScale scale, id target, SEL action) +{ + UIBarButtonItem* rv; + if(scale > LNSystemImageScaleNormal) + { + UIButtonConfiguration* config = [UIButtonConfiguration plainButtonConfiguration]; + config.image = LNSystemImage(name, scale); + + UIButton* button = [UIButton buttonWithConfiguration:config primaryAction:nil]; + [button addTarget:target action:action forControlEvents:UIControlEventPrimaryActionTriggered]; + + button.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [button.widthAnchor constraintEqualToConstant:_LNWidthForScale(scale)] + ]]; + + rv = [[UIBarButtonItem alloc] initWithCustomView:button]; + } + else{ + rv = [[UIBarButtonItem alloc] initWithImage:LNSystemImage(name, scale) style:UIBarButtonItemStylePlain target:target action:action]; + rv.width = _LNWidthForScale(scale); + } + return rv; +} + +UIBarButtonItem* LNSystemBarButtonItemAction(NSString* name, LNSystemImageScale scale, UIAction* primaryAction) +{ + UIBarButtonItem* rv; + if(scale > LNSystemImageScaleNormal) + { + UIButtonConfiguration* config = [UIButtonConfiguration plainButtonConfiguration]; + config.image = LNSystemImage(name, scale); + + UIButton* button = [UIButton buttonWithConfiguration:config primaryAction:primaryAction]; + + button.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [button.widthAnchor constraintEqualToConstant:_LNWidthForScale(scale)] + ]]; + + rv = [[UIBarButtonItem alloc] initWithCustomView:button]; + } + else{ + rv = [[UIBarButtonItem alloc] initWithPrimaryAction:primaryAction]; + rv.image = LNSystemImage(name, scale); + rv.width = _LNWidthForScale(scale); + } + return rv; +} diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.pbxproj b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3104475 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.pbxproj @@ -0,0 +1,646 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 3908C34C1E7C9EA200451B5D /* SettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3908C34B1E7C9EA200451B5D /* SettingsTableViewController.m */; }; + 39140B901DBD69540036A6C5 /* Music.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 397C560D1B74DA66007A67F0 /* Music.storyboard */; }; + 39277A091B58228000293F95 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 39277A081B58228000293F95 /* main.m */; }; + 39277A0C1B58228000293F95 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 39277A0B1B58228000293F95 /* AppDelegate.m */; }; + 39277A151B58228000293F95 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39277A131B58228000293F95 /* Main.storyboard */; }; + 39277A171B58228000293F95 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39277A161B58228000293F95 /* Assets.xcassets */; }; + 393F23231E16BF1D000E969D /* MapScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 393F23221E16BF1D000E969D /* MapScene.storyboard */; }; + 393F23251E16C04A000E969D /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23241E16C04A000E969D /* MapViewController.swift */; }; + 393F23271E16C192000E969D /* CustomMapBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23261E16C192000E969D /* CustomMapBarViewController.swift */; }; + 393F23291E16CF90000E969D /* LocationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F23281E16CF90000E969D /* LocationsController.swift */; }; + 393F232B1E16D1E4000E969D /* HigherSearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 393F232A1E16D1E4000E969D /* HigherSearchBar.swift */; }; + 394198482B4EFCA300FBC92D /* TOInsetGroupedTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 394198472B4EFCA300FBC92D /* TOInsetGroupedTableView.m */; }; + 3941984C2B4EFD6D00FBC92D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3941984B2B4EFD6D00FBC92D /* LaunchScreen.storyboard */; }; + 39631FAD230DA03E0059D119 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 39631FAC230DA03E0059D119 /* SceneDelegate.m */; }; + 39756327254ED9EB0066981E /* DemoGallery.m in Sources */ = {isa = PBXBuildFile; fileRef = 39756326254ED9EB0066981E /* DemoGallery.m */; }; + 397C56281B7538A5007A67F0 /* DemoAlbumTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C56271B7538A5007A67F0 /* DemoAlbumTableViewController.swift */; }; + 397C562A1B753A45007A67F0 /* MusicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397C56291B753A45007A67F0 /* MusicCell.swift */; }; + 39837A201B756F1A004D2DA9 /* RandomColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 39837A1F1B756F1A004D2DA9 /* RandomColors.m */; }; + 39837A241B758541004D2DA9 /* DemoMusicPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39837A231B758541004D2DA9 /* DemoMusicPlayerController.swift */; }; + 39837A261B759721004D2DA9 /* PortraitTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39837A251B759721004D2DA9 /* PortraitTabBarController.swift */; }; + 3985DE602549539B00CD76EE /* IntroWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3985DE5F2549539B00CD76EE /* IntroWebViewController.m */; }; + 3988E3581B59C3000039C09B /* FirstViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3988E3571B59C3000039C09B /* FirstViewController.m */; }; + 399748721D5652250079492B /* DemoPopupContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 399748711D5652250079492B /* DemoPopupContentViewController.m */; }; + 39A3B58B230D400B00E10425 /* SplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 39A3B58A230D400B00E10425 /* SplitViewController.m */; }; + 39BBA86924FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BBA86824FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift */; }; + 39BBA86A24FEC3E500D9712A /* ManualLayoutScene.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39BBA86524FEC25400D9712A /* ManualLayoutScene.storyboard */; }; + 39DA0E8322D7B9C6001E63A0 /* NSObject+XcodeBugs.m in Sources */ = {isa = PBXBuildFile; fileRef = 39DA0E8222D7B9C6001E63A0 /* NSObject+XcodeBugs.m */; }; + 39DB61801B8891ED001BFF8F /* LNPopupController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39DB52F51B5823490061C589 /* LNPopupController.framework */; }; + 39DB61811B8891ED001BFF8F /* LNPopupController.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 39DB52F51B5823490061C589 /* LNPopupController.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 39DDA0AE230D5F63007DCCD8 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39DDA0AD230D5F63007DCCD8 /* MapKit.framework */; }; + 39F8A07424DB3B1F0008B209 /* LoremIpsum in Frameworks */ = {isa = PBXBuildFile; productRef = 39F8A07324DB3B1F0008B209 /* LoremIpsum */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 39DB52F41B5823490061C589 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 39DB52F01B5823480061C589 /* LNPopupController.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 39DB52E51B5823330061C589; + remoteInfo = LNPopupController; + }; + 39DB61821B8891EE001BFF8F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 39DB52F01B5823480061C589 /* LNPopupController.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 39DB52E41B5823330061C589; + remoteInfo = LNPopupController; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 39DB61841B8891EE001BFF8F /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 39DB61811B8891ED001BFF8F /* LNPopupController.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 3908C34A1E7C9EA200451B5D /* SettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewController.h; sourceTree = ""; }; + 3908C34B1E7C9EA200451B5D /* SettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewController.m; sourceTree = ""; }; + 39277A041B58228000293F95 /* LNPopupControllerExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LNPopupControllerExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 39277A081B58228000293F95 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 39277A0A1B58228000293F95 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 39277A0B1B58228000293F95 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 39277A0D1B58228000293F95 /* FirstViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FirstViewController.h; sourceTree = ""; }; + 39277A141B58228000293F95 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 39277A161B58228000293F95 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 39277A1B1B58228000293F95 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 393F23221E16BF1D000E969D /* MapScene.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MapScene.storyboard; sourceTree = ""; }; + 393F23241E16C04A000E969D /* MapViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; + 393F23261E16C192000E969D /* CustomMapBarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomMapBarViewController.swift; sourceTree = ""; }; + 393F23281E16CF90000E969D /* LocationsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationsController.swift; sourceTree = ""; }; + 393F232A1E16D1E4000E969D /* HigherSearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HigherSearchBar.swift; sourceTree = ""; }; + 394198462B4EFCA300FBC92D /* TOInsetGroupedTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOInsetGroupedTableView.h; sourceTree = ""; }; + 394198472B4EFCA300FBC92D /* TOInsetGroupedTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOInsetGroupedTableView.m; sourceTree = ""; }; + 3941984B2B4EFD6D00FBC92D /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 39631FAB230DA03D0059D119 /* SceneDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; + 39631FAC230DA03E0059D119 /* SceneDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; + 39756325254ED9EB0066981E /* DemoGallery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DemoGallery.h; sourceTree = ""; }; + 39756326254ED9EB0066981E /* DemoGallery.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoGallery.m; sourceTree = ""; }; + 397C560D1B74DA66007A67F0 /* Music.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Music.storyboard; sourceTree = ""; }; + 397C56271B7538A5007A67F0 /* DemoAlbumTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoAlbumTableViewController.swift; sourceTree = ""; }; + 397C56291B753A45007A67F0 /* MusicCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MusicCell.swift; sourceTree = ""; }; + 39837A1F1B756F1A004D2DA9 /* RandomColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RandomColors.m; sourceTree = ""; }; + 39837A211B756F4C004D2DA9 /* RandomColors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RandomColors.h; sourceTree = ""; }; + 39837A231B758541004D2DA9 /* DemoMusicPlayerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoMusicPlayerController.swift; sourceTree = ""; }; + 39837A251B759721004D2DA9 /* PortraitTabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PortraitTabBarController.swift; sourceTree = ""; }; + 3985DE5E2549539B00CD76EE /* IntroWebViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntroWebViewController.h; sourceTree = ""; }; + 3985DE5F2549539B00CD76EE /* IntroWebViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntroWebViewController.m; sourceTree = ""; }; + 3988E3571B59C3000039C09B /* FirstViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirstViewController.m; sourceTree = ""; }; + 399748701D5652250079492B /* DemoPopupContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoPopupContentViewController.h; sourceTree = ""; }; + 399748711D5652250079492B /* DemoPopupContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoPopupContentViewController.m; sourceTree = ""; }; + 39A134DA1B73FFC0003AB4C5 /* LNPopupControllerExample-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LNPopupControllerExample-Bridging-Header.h"; sourceTree = ""; }; + 39A3B589230D400B00E10425 /* SplitViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SplitViewController.h; sourceTree = ""; }; + 39A3B58A230D400B00E10425 /* SplitViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SplitViewController.m; sourceTree = ""; }; + 39A3B58C230D433100E10425 /* LNPopupControllerExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LNPopupControllerExample.entitlements; sourceTree = ""; }; + 39BBA86524FEC25400D9712A /* ManualLayoutScene.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ManualLayoutScene.storyboard; sourceTree = ""; }; + 39BBA86824FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualLayoutCustomBarViewController.swift; sourceTree = ""; }; + 39DA0E8122D7B9C6001E63A0 /* NSObject+XcodeBugs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+XcodeBugs.h"; sourceTree = ""; }; + 39DA0E8222D7B9C6001E63A0 /* NSObject+XcodeBugs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+XcodeBugs.m"; sourceTree = ""; }; + 39DB52F01B5823480061C589 /* LNPopupController.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = LNPopupController.xcodeproj; path = ../LNPopupController/LNPopupController.xcodeproj; sourceTree = ""; }; + 39DDA0AD230D5F63007DCCD8 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; + 39FAFC5824E71A6C008BBC2D /* LNPopupControllerExampleNoPopup-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "LNPopupControllerExampleNoPopup-Info.plist"; path = "/Users/lnatan/Desktop/GitHub (Private)/LNPopupController/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 39277A011B58228000293F95 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 39DDA0AE230D5F63007DCCD8 /* MapKit.framework in Frameworks */, + 39DB61801B8891ED001BFF8F /* LNPopupController.framework in Frameworks */, + 39F8A07424DB3B1F0008B209 /* LoremIpsum in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3908C3491E7C9E8A00451B5D /* Settings */ = { + isa = PBXGroup; + children = ( + 3908C34A1E7C9EA200451B5D /* SettingsTableViewController.h */, + 3908C34B1E7C9EA200451B5D /* SettingsTableViewController.m */, + ); + name = Settings; + sourceTree = ""; + }; + 392779FB1B58228000293F95 = { + isa = PBXGroup; + children = ( + 39DB52F01B5823480061C589 /* LNPopupController.xcodeproj */, + 39277A061B58228000293F95 /* LNPopupControllerExample */, + 39277A051B58228000293F95 /* Products */, + 39DDA0AC230D5F63007DCCD8 /* Frameworks */, + ); + sourceTree = ""; + }; + 39277A051B58228000293F95 /* Products */ = { + isa = PBXGroup; + children = ( + 39277A041B58228000293F95 /* LNPopupControllerExample.app */, + ); + name = Products; + sourceTree = ""; + }; + 39277A061B58228000293F95 /* LNPopupControllerExample */ = { + isa = PBXGroup; + children = ( + 39A3B58C230D433100E10425 /* LNPopupControllerExample.entitlements */, + 39277A131B58228000293F95 /* Main.storyboard */, + 397C560B1B74D47D007A67F0 /* Demo - Testing Scene (Objective-C) */, + 397C560C1B74D747007A67F0 /* Demo - Music Scene (Swift) */, + 393F23211E16BEF5000E969D /* Demo - Custom Pupup Bar Scene (Swift) */, + 39BBA86324FEC16600D9712A /* Demo - Custom Pupup Bar Scene - Manual Layout (Swift) */, + 3908C3491E7C9E8A00451B5D /* Settings */, + 39837A221B756F9B004D2DA9 /* Utils */, + 39277A071B58228000293F95 /* Supporting Files */, + ); + path = LNPopupControllerExample; + sourceTree = ""; + }; + 39277A071B58228000293F95 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 394198462B4EFCA300FBC92D /* TOInsetGroupedTableView.h */, + 394198472B4EFCA300FBC92D /* TOInsetGroupedTableView.m */, + 397C560A1B74D45F007A67F0 /* Swift Bridging Header */, + 39277A161B58228000293F95 /* Assets.xcassets */, + 3941984B2B4EFD6D00FBC92D /* LaunchScreen.storyboard */, + 39277A1B1B58228000293F95 /* Info.plist */, + 39FAFC5824E71A6C008BBC2D /* LNPopupControllerExampleNoPopup-Info.plist */, + 39277A0A1B58228000293F95 /* AppDelegate.h */, + 39277A0B1B58228000293F95 /* AppDelegate.m */, + 39631FAB230DA03D0059D119 /* SceneDelegate.h */, + 39631FAC230DA03E0059D119 /* SceneDelegate.m */, + 39277A081B58228000293F95 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 393F23211E16BEF5000E969D /* Demo - Custom Pupup Bar Scene (Swift) */ = { + isa = PBXGroup; + children = ( + 393F23221E16BF1D000E969D /* MapScene.storyboard */, + 393F23241E16C04A000E969D /* MapViewController.swift */, + 393F23261E16C192000E969D /* CustomMapBarViewController.swift */, + 393F23281E16CF90000E969D /* LocationsController.swift */, + 393F232A1E16D1E4000E969D /* HigherSearchBar.swift */, + ); + name = "Demo - Custom Pupup Bar Scene (Swift)"; + sourceTree = ""; + }; + 397C560A1B74D45F007A67F0 /* Swift Bridging Header */ = { + isa = PBXGroup; + children = ( + 39A134DA1B73FFC0003AB4C5 /* LNPopupControllerExample-Bridging-Header.h */, + ); + name = "Swift Bridging Header"; + sourceTree = ""; + }; + 397C560B1B74D47D007A67F0 /* Demo - Testing Scene (Objective-C) */ = { + isa = PBXGroup; + children = ( + 39756325254ED9EB0066981E /* DemoGallery.h */, + 39756326254ED9EB0066981E /* DemoGallery.m */, + 39277A0D1B58228000293F95 /* FirstViewController.h */, + 3988E3571B59C3000039C09B /* FirstViewController.m */, + 399748701D5652250079492B /* DemoPopupContentViewController.h */, + 399748711D5652250079492B /* DemoPopupContentViewController.m */, + 39A3B589230D400B00E10425 /* SplitViewController.h */, + 39A3B58A230D400B00E10425 /* SplitViewController.m */, + 3985DE5E2549539B00CD76EE /* IntroWebViewController.h */, + 3985DE5F2549539B00CD76EE /* IntroWebViewController.m */, + ); + name = "Demo - Testing Scene (Objective-C)"; + sourceTree = ""; + }; + 397C560C1B74D747007A67F0 /* Demo - Music Scene (Swift) */ = { + isa = PBXGroup; + children = ( + 397C560D1B74DA66007A67F0 /* Music.storyboard */, + 397C56271B7538A5007A67F0 /* DemoAlbumTableViewController.swift */, + 39837A231B758541004D2DA9 /* DemoMusicPlayerController.swift */, + 397C56291B753A45007A67F0 /* MusicCell.swift */, + 39837A251B759721004D2DA9 /* PortraitTabBarController.swift */, + ); + name = "Demo - Music Scene (Swift)"; + sourceTree = ""; + }; + 39837A221B756F9B004D2DA9 /* Utils */ = { + isa = PBXGroup; + children = ( + 39DA0E8122D7B9C6001E63A0 /* NSObject+XcodeBugs.h */, + 39DA0E8222D7B9C6001E63A0 /* NSObject+XcodeBugs.m */, + 39837A211B756F4C004D2DA9 /* RandomColors.h */, + 39837A1F1B756F1A004D2DA9 /* RandomColors.m */, + ); + name = Utils; + sourceTree = ""; + }; + 39BBA86324FEC16600D9712A /* Demo - Custom Pupup Bar Scene - Manual Layout (Swift) */ = { + isa = PBXGroup; + children = ( + 39BBA86524FEC25400D9712A /* ManualLayoutScene.storyboard */, + 39BBA86824FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift */, + ); + name = "Demo - Custom Pupup Bar Scene - Manual Layout (Swift)"; + sourceTree = ""; + }; + 39DB52F11B5823480061C589 /* Products */ = { + isa = PBXGroup; + children = ( + 39DB52F51B5823490061C589 /* LNPopupController.framework */, + ); + name = Products; + sourceTree = ""; + }; + 39DDA0AC230D5F63007DCCD8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 39DDA0AD230D5F63007DCCD8 /* MapKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 39277A031B58228000293F95 /* LNPopupControllerExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 39277A1E1B58228000293F95 /* Build configuration list for PBXNativeTarget "LNPopupControllerExample" */; + buildPhases = ( + 39277A001B58228000293F95 /* Sources */, + 39277A011B58228000293F95 /* Frameworks */, + 39277A021B58228000293F95 /* Resources */, + 39DB61841B8891EE001BFF8F /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 39DB61831B8891EE001BFF8F /* PBXTargetDependency */, + ); + name = LNPopupControllerExample; + packageProductDependencies = ( + 39F8A07324DB3B1F0008B209 /* LoremIpsum */, + ); + productName = LNPopupControllerExample; + productReference = 39277A041B58228000293F95 /* LNPopupControllerExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 392779FC1B58228000293F95 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 9999; + ORGANIZATIONNAME = "Leo Natan"; + TargetAttributes = { + 39277A031B58228000293F95 = { + CreatedOnToolsVersion = 7.0; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 392779FF1B58228000293F95 /* Build configuration list for PBXProject "LNPopupControllerExample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 392779FB1B58228000293F95; + packageReferences = ( + 39F8A07224DB3B1F0008B209 /* XCRemoteSwiftPackageReference "LoremIpsum" */, + ); + productRefGroup = 39277A051B58228000293F95 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 39DB52F11B5823480061C589 /* Products */; + ProjectRef = 39DB52F01B5823480061C589 /* LNPopupController.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 39277A031B58228000293F95 /* LNPopupControllerExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 39DB52F51B5823490061C589 /* LNPopupController.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = LNPopupController.framework; + remoteRef = 39DB52F41B5823490061C589 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 39277A021B58228000293F95 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 39140B901DBD69540036A6C5 /* Music.storyboard in Resources */, + 39BBA86A24FEC3E500D9712A /* ManualLayoutScene.storyboard in Resources */, + 393F23231E16BF1D000E969D /* MapScene.storyboard in Resources */, + 3941984C2B4EFD6D00FBC92D /* LaunchScreen.storyboard in Resources */, + 39277A171B58228000293F95 /* Assets.xcassets in Resources */, + 39277A151B58228000293F95 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 39277A001B58228000293F95 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3908C34C1E7C9EA200451B5D /* SettingsTableViewController.m in Sources */, + 39BBA86924FEC32F00D9712A /* ManualLayoutCustomBarViewController.swift in Sources */, + 39756327254ED9EB0066981E /* DemoGallery.m in Sources */, + 397C56281B7538A5007A67F0 /* DemoAlbumTableViewController.swift in Sources */, + 39837A241B758541004D2DA9 /* DemoMusicPlayerController.swift in Sources */, + 393F23271E16C192000E969D /* CustomMapBarViewController.swift in Sources */, + 393F232B1E16D1E4000E969D /* HigherSearchBar.swift in Sources */, + 39A3B58B230D400B00E10425 /* SplitViewController.m in Sources */, + 39277A0C1B58228000293F95 /* AppDelegate.m in Sources */, + 394198482B4EFCA300FBC92D /* TOInsetGroupedTableView.m in Sources */, + 39DA0E8322D7B9C6001E63A0 /* NSObject+XcodeBugs.m in Sources */, + 39277A091B58228000293F95 /* main.m in Sources */, + 39837A201B756F1A004D2DA9 /* RandomColors.m in Sources */, + 393F23291E16CF90000E969D /* LocationsController.swift in Sources */, + 3985DE602549539B00CD76EE /* IntroWebViewController.m in Sources */, + 393F23251E16C04A000E969D /* MapViewController.swift in Sources */, + 399748721D5652250079492B /* DemoPopupContentViewController.m in Sources */, + 3988E3581B59C3000039C09B /* FirstViewController.m in Sources */, + 39837A261B759721004D2DA9 /* PortraitTabBarController.swift in Sources */, + 39631FAD230DA03E0059D119 /* SceneDelegate.m in Sources */, + 397C562A1B753A45007A67F0 /* MusicCell.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 39DB61831B8891EE001BFF8F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = LNPopupController; + targetProxy = 39DB61821B8891EE001BFF8F /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 39277A131B58228000293F95 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 39277A141B58228000293F95 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 39277A1C1B58228000293F95 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 39277A1D1B58228000293F95 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 39277A1F1B58228000293F95 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_ENTITLEMENTS = LNPopupControllerExample/LNPopupControllerExample.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; + DEVELOPMENT_TEAM = S9QFG2VH2E; + GCC_PREPROCESSOR_DEFINITIONS = ( + "LNPOPUP=1", + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = LNPopupControllerExample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = "-DLNPOPUP"; + PRODUCT_BUNDLE_IDENTIFIER = "com.LeoNatan.LNPopupControllerExample-"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SUPPORTS_MACCATALYST = YES; + SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 39277A201B58228000293F95 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_ENTITLEMENTS = LNPopupControllerExample/LNPopupControllerExample.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; + DEVELOPMENT_TEAM = S9QFG2VH2E; + GCC_PREPROCESSOR_DEFINITIONS = "LNPOPUP=1"; + INFOPLIST_FILE = LNPopupControllerExample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + OTHER_SWIFT_FLAGS = "-DLNPOPUP"; + PRODUCT_BUNDLE_IDENTIFIER = "com.LeoNatan.LNPopupControllerExample-"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SUPPORTS_MACCATALYST = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OBJC_BRIDGING_HEADER = "LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 392779FF1B58228000293F95 /* Build configuration list for PBXProject "LNPopupControllerExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 39277A1C1B58228000293F95 /* Debug */, + 39277A1D1B58228000293F95 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 39277A1E1B58228000293F95 /* Build configuration list for PBXNativeTarget "LNPopupControllerExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 39277A1F1B58228000293F95 /* Debug */, + 39277A201B58228000293F95 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 39F8A07224DB3B1F0008B209 /* XCRemoteSwiftPackageReference "LoremIpsum" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/lukaskubanek/LoremIpsum"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.0.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 39F8A07324DB3B1F0008B209 /* LoremIpsum */ = { + isa = XCSwiftPackageProductDependency; + package = 39F8A07224DB3B1F0008B209 /* XCRemoteSwiftPackageReference "LoremIpsum" */; + productName = LoremIpsum; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 392779FC1B58228000293F95 /* Project object */; +} diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExample.xcscheme b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExample.xcscheme new file mode 100644 index 0000000..25b5229 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExample.xcscheme @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExampleNoPopup.xcscheme b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExampleNoPopup.xcscheme new file mode 100644 index 0000000..14a9386 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample.xcodeproj/xcshareddata/xcschemes/LNPopupControllerExampleNoPopup.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/AppDelegate.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/AppDelegate.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/AppDelegate.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/AppDelegate.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/AppDelegate.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/AppDelegate.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/AppDelegate.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/AppDelegate.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/1.square.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/1.square.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/1.square.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/1.square.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/1.square.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/2.square.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/2.square.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/2.square.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/2.square.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/2.square.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/3.square.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/3.square.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/3.square.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/3.square.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/3.square.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/4.square.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/4.square.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/4.square.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/4.square.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/4.square.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_1024.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_1024.png new file mode 100644 index 0000000..113b680 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_1024.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x-1.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x-1.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x-1.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x-1.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@3x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_20@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x-1.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x-1.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x-1.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x-1.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@3x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_29@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x-1.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x-1.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x-1.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x-1.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@3x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_40@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@2x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@3x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@3x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_60@3x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76@2x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_76@2x.png diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/airplayaudio.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/airplayaudio.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/airplayaudio.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/airplayaudio.imageset/airplayaudio.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/backward.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/backward.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/backward.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/backward.fill.imageset/backward.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/chevron.left.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/chevron.left.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/chevron.left.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/chevron.left.imageset/chevron.left.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/clock.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/clock.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/clock.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/clock.fill.imageset/clock.fill.svg diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/Contents.json new file mode 100644 index 0000000..9f3069e --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg new file mode 100644 index 0000000..ae38d35 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/demoAlbum.imageset/smackandtoss-blue-orange-abstract-fog-ipad-wallpaper.jpg differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/dock.arrow.down.rectangle.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/dock.arrow.down.rectangle.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/dock.arrow.down.rectangle.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.down.rectangle.imageset/dock.arrow.down.rectangle.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/dock.arrow.up.rectangle.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/dock.arrow.up.rectangle.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/dock.arrow.up.rectangle.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/dock.arrow.up.rectangle.imageset/dock.arrow.up.rectangle.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/ellipsis.circle.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/ellipsis.circle.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/ellipsis.circle.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.circle.fill.imageset/ellipsis.circle.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/ellipsis.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/ellipsis.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/ellipsis.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/ellipsis.imageset/ellipsis.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/forward.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/forward.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/forward.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/forward.fill.imageset/forward.fill.svg diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/gears.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/gears.imageset/Contents.json new file mode 100644 index 0000000..1121072 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/gears.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "gears.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/gears.imageset/gears.pdf b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/gears.imageset/gears.pdf new file mode 100644 index 0000000..c5a70f6 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/gears.imageset/gears.pdf @@ -0,0 +1,190 @@ +%PDF-1.5 %âãÏÓ +1 0 obj <> endobj 2 0 obj <>stream + + + + + Adobe Illustrator CC 23.0 (Macintosh) + 2019-08-22T07:46:24+03:00 + 2019-08-22T07:46:24+03:00 + 2019-08-22T07:46:24+03:00 + + + + 256 + 240 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA8AEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXzF/wA5jf8AHS8r/wDGG7/4lFikPnPFLsVZz+SH/k2PLP8AzGD/AIg2KC+8MUOxV2KuxV2KuxV2 KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV4x+dH/OQmneURNofl4pfeZacZpdmgtKj 9v8Ank8E6D9rwKmmR/kv+bVl5/8AL4MxSHzDYqq6naLtXsJ4wf2H/wCFO3hVQ9ExV2KvmL/nMb/j peV/+MN3/wASixSHznil2Ks5/JD/AMmx5Z/5jB/xBsUF94YodiqV+ZvMuj+WdDuta1icW9haJykb qzHoqIP2nY7KPHFXgHkn/nK55/NV1D5pt1ttAvZf9BniHJ7NdlVZeIrIm1WanIH22Cmn0da3Vrd2 0V1aypPbTKHhmjYOjqwqGVhUEHFCrirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirTuiIz uwVFBLMTQADckk4q+avzr/5ySJ9fy75HuKDeO912M7nahS1I6f8AGT/gf5sUgPm5mZ2LMSzMasx3 JJ7nFKb+UfNms+VPMFrrmkTeld2rV4mvCRD9uOQDqjDr/XFX1nJ/zk9+W0Ple01aSWWTUbmOr6LA vOeOUbMrs3CMKG6MTuNwO2LGnkPmz/nK7z3qbvFoMFvodqahHCi5uae7yj0/uj+nFNPJvMHmnzJ5 iulutd1K51KdARG1xI0gQHqEUnigNOigYpSrFXYqr2d7eWN1Fd2U8lrdwtyhuIXaORGHdXUhgfli r0vyz/zkl+aWiOqz36axailYNQQSGnekqcJa/Nj8sUU9v8jf85SeSNcKWuvI3l++I/vJT6tox9pl AKf7NQPc4rTw388fzguvPut/VrJmh8tae5FjAdjM+4NxIPFh9kfsj3JxUB5hil6h+T/55a35DuVs bvnqHlmVqzWJNXhLdZLcnofFPsn2O+KCH2N5b8y6H5l0iDV9Fu0vLC4HwSId1bujqd1de6ncYoTP FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8Z/5yfsfPU/ksT6FcsNDg5HXrOFSJni24uzjc xLvzUU8TUdFQ+PMWTsVdirsVdirsVdirsVdirsVdirsVdirsVe2/84t2fnqbzhJNo1w1v5cgodc9 UFoJQR8ESrt++PUMPsjrt8LKC+vMUOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVqSNJEaORQ 6OCrowqCDsQQcVfHP/OQH5MP5N1M65osRPlm/f8Au1BP1SZjX0j/AMVt+wf9j4VUgvHcUuxV2Kux V2KuxV2KuxV2KuxV2KuxVkv5f+Q9a87+ZLfRNLWhf47q5YfBBCCOcj/LsO52xV91eTvKOjeUvL9r oekRena2y/E5pzlkI+OWQjq7nc/cNsWKdYq7FXYq7FXYqg9W1jStHsZL/VbyGxsohWS4ndY0HtVi Nz2GKsL8kfnd5K85+Z7zQNGeZpbaH1oLmVPTjuFVqSekGPP4aqfiAJ322xV6Birwv/nIj84fNHkj WtE0/wAu3EcUs0EtzfRSxJKrozqkP2hyWhjk+yRikMN0T/nMDzDCEXWtAtbwDZ5LSWS2anjxcXAJ +76MVp7x+WX5jWHn/wAvya1ZWVxYxRXDWrJccDydEVyUKk8l/eAVoN64oZdirsVdirsVdirsVfLH /OUP5qvqGot5G0qX/QLJ1bWHX/dtwtGWGv8ALF1P+V/q4pD59xS7FXYq7FV8UMs0ixQo0krmiIgL MT4ADfFWYaZ+Tf5panEstp5avvTYVVpo/q4I8R6xjxW0VcfkR+bkEZkfy1clR2jaKRv+BR2b8MVt h2p6Pq+lXH1bVLG4sLj/AHzdRPC+3+S4U4qg8VdirsVdirM/yn/Ma+8h+bYNVi5SafNSDVLUHaSA kVIHTmn2l+7oTipfd+n39nqNhb39lKs9ndxpNbzIaq8cihlYfMHFir4q7FXYq7FUu8xya3FoOoS6 EkUusRwSPYRTgmJ5lUlFbiVPxHbrir4I85ed/N/mrUnuPMd9NczxswW2f4IoSDQqkIoqU6dK+OLJ CeVfMmo+WvMVhruntxurCZZUWtA6jZ42/wAl1qp9jir33Vf+cxZOfHSfLQCDrJdXNSf9hGm3/BYo p4r+Y/5g6r588xfpzUoIreYQR2yQwcuCpGWO3Msd2cnFIYtir7Y/5xufRU/KvS7SxvILm8T1ZdRi idWeOWaVmCyKN1ITiN8WL06eeC3gknuJFhgiUvLLIwVFVRUszGgAA74ql3lvzToHmXTv0loV7HfW XqPCZo60DxniwIYAjxG24oRscVTTFWH/AJh/mp5X8grpza8LgrqbyJAbdFkKiEKXZwXQ8RzUfCD1 xVLdI/P/APKTUwPT8wRWznrHdpLb0+bSKqfc2Kq/5g/mp5f0LyHqev6Tqdpf3Ecfp6f9WljuFa4m +GKvAsCAfiPsMVfCtxcTXE8lxO5lnmZpJZGNWZ2NWYnxJOLJTxV2KuxV6v8AlD+QWueeSmp6g76X 5bB2uuNZrihoVt1bam1C7bDsDii31b5O/LjyZ5Ptlh0HTIreXiFkvGHO5kp/PM1WPy6eAxQyXFXY qgtY0PRtasmsdXsYL+0f7UFxGsi18QGBofcb4q+dvzW/5xbWKGbV/IfJuFXm0KRixp1/0aRtzT+R zU9j0GKbfN0kckcjRyKUkQlXRgQwYGhBB6EYpW4q7FXYq+pf+cWfzJt5fL175W1e7SFtI/0mwlnc IPqsjUdKsekcjf8ADe2KC9R1b85vys0osLvzNYlkryW3k+tMCOo424lNfbFCUeW/+cgvy98x+abL y5pD3c93fmQQ3DQ+nADHG0lGMjK+4Sgoh3xV6VirsVU7m5t7a3kubmRYbeFTJNNIQqIiirMzHYAD FXwX+bmseV9Z/MHV9T8sxsmmXMvPkw4rJMR+9lReqrI9W333rt0xZBh2KuxV2KuxVMdA8xa55f1K LU9FvZbC+h+xNC1DTurD7LKe6sCDirMfzC/PDzv540+203UZUtdPhRfrFtaBkS4lX/dk1Sa77hfs jwritLvyW/Ne88geZA8zNL5fvyseq2o3oOizxj+eOv8AshUeBCpfb9jfWl/ZwXtnMtxaXKLLBMhq ro4qrA+4xYvlb/nL3VxP5y0fSlaq2NgZmHg9zKwI/wCBhU4pDwXFLsVdirsVdir078iPypbz35mM t8pXy/pZWXUG3HqsT8Fup/yqVbwX3IxQX2vbW1vbW8dtbRrDbwqI4YYwFREUUVVUbAAYoVMVdirs VdirsVfO3/OTf5QW81lL550OAR3UG+uQRigkjO31kAftr+34jfsaqQ+X8UuxV2KuxV2Ksk/LfVv0 R5/8vajUBLfULcyk/wC+2kCyf8IxxUv0FxYvij8zvzd8yXP5panrPl7Vbiyt7R/qVi1vIQjw25K1 ZfsOruWf4h3xSAh/N35/efvNXlQeXdTlhSJ3DXd1boYpLiNRtHKFPDjy3PECu2K081xS7FXovk/8 gvzM80WyXdtpy2FjKAYrrUGMCsD0KpRpSPcJTFFssu/+cR/zDitxJb6jpdzKFq8IknQ122Rmh4n/ AGXHFbeXebvIXm7yjdi28w6ZLZM5pFMQHhk/4xyoWjb5A1HfFLH8VdirLPy8/LPzP571X6lo8NLe Ir9d1CSoggU92PdvBRucVt9t+QPJdl5M8rWnl+zuZruK25MZ52qS7nk/FeiLy6KOnuanFi+Pv+ch NWOpfm5rzVrHavFaRjrQQRKrf8PyOKQ85xS7FXYq7FXYq+7/AMk/JsXlT8udKsuAW9u4xfag3cz3 ChiD/qJxT6MWLOsVdirsVdirsVdiqnc20F1bS21xGJbedGjmiYVVkccWUjwIOKvz68/+WH8rec9Y 0AklLC4ZIWPUwtR4WPzjZTiyDH8VdirsVdirasysGUkMDUEbEEYq+7fNnmXXLj8n5db8v2s1/q2p aZFJZxWqF5Q13GtZFVd6xq5agHbFi+FZ4J7eZ4J42imjJWSJwVZSOoKncHFkp4q7FX0r/wA42/kr Y3FlB538xQLcGUk6LYyiqBVJX6xIpHxEkH0wdv2vCigvpTFDsVQGuaDo+vaXPper2sd7YXApLBKK g+BHcMOxG4xV8P8A5w/lpc+QfNsmnBmm0q6BuNKuW6tCTQo9P24z8LeOx2riyDBcVe1/84qebH0v z9LoUj0tNdgZVU1p9Ytg0sZ8PseoPpGKC+vsUPzt823V1eeZ9Wv7qJ4Zr68numjlVkYetKz7qwB/ axZBKMVdirsVdiqY+XbBNR8waZp7iqXl3BbsOm0siof14q/RgAAAAUA2AGLF2KuxV2KuxV2KuxV2 Kvjz/nK+xjtvzRimWnK9023nkp/MsksO/wBEIxSHjOKXYq7FXYq2ASaDcnoMVfc/5B3tzdflPoIu onhuLWOS2eOUENSGVljPxAGhj4kYsUr/AOcj9E0CT8sdZ1m5023uNTs1gW0vWRRNGZrmKElZKcqU fp0xUPivFkidOs2vtQtbJG4vdSxwqx3oZGCg/jir9GNN0+103TrXT7RPTtbOJIIE8I41CqNvYYsU RirsVdirxT/nLDRILz8urfUyn+kaXexlJKVIjnBjda9gW4H6MUh8g4pRWmanqGl38OoadcPa3tu3 OC4iJV0alKqR064qy4fnf+bAAH+JrzbxZT/xriin3Tfabp1/F6V9aw3cW/7ueNZF367MCMUMP1f8 kPyo1UN9Z8tWkTP1a0VrQg+I+rmPFXxB5l09NN8x6rp0a8Usry4t1WpNBFKyAVO/7PfFkluKuxVM vLd8mn+YtLv3NEtLuCdiewjlVz4eGKv0XBBAINQdwRixdirsVdirsVdirsVdir49/wCcsL2O4/NC KFacrPTLeB6eJklm3+iUYpDxjFLsVdir65/Jj8l/y4vvIOia5qmiRXuq30JmnlnklkQ1dgtIi/pj 4QP2cWL13SfK3lnR1UaTpNnYBBRfq0EUR367ooxVb5l80+X/ACxpjapr16ljYqwj9ZwzVdgSFVUD MSQp2AxV86fnT/zkT5U80eUtR8q6FZ3M63xhDajNxhjX0Z0nqkfxO1fTp8XHrikB87YpRGn3j2V/ bXqAM9tKkyqehMbBgPwxV+jGmaja6nptpqNo4ktb2GO4gcbho5VDqdvY4sUTirsVdirxL/nLLXYL P8vrXSeQ+s6pepxjrv6VuDI7fQ5QfTikPkPFLsVRGnQxzahbQyCsckqI46VDMAcVfpDixdir4S/P TR20r82PMcBTis90bxD2IulE5I/2TnFkGB4q7FXYq+8PyU84R+avy40m+L8ry2iFlfjaontwEJNP 514v9OLFnOKuxV2KuxV2KuxVTubmC1tpbm4kEVvAjSTSsaKqIOTMT4ADFX59/mD5nbzT511jXzUJ fXLPAp6iFaJCD7iNVGLIMexV2KuxV+h/kjRzovk7Q9JZSsljY28EoPX1EiUPX/ZVxYp1irEPzb8q /wCKPy71vSETnctbmezHf14P3sYH+sycfpxV8C4snYq7FX0j/wA43/nZY2dnF5K8y3K28cbU0W+l NEo5/wB55GOy7n4Cdv2fDFBD6YBBFRuDih2Kpd5h8xaL5d0mfVtZu0s7C3FXlkNKnsqjqzN2UbnF Xw9+bn5k3Xn/AM2SaoUaDTrdfq+mWrdUhBJ5PQkc3Jq1Pl2xZBhGKvaf+cXPI1vr/nK61bULVLnT NHtyCkyCSNri4BRFKtVTRObexpigvqY+SPJZ2OgaaR13tIO2/wDJihOsVQOta5o+h6fJqOr3kVjY xfbnnYIteoAr1Y02A3OKvi78+/Pnljzr5zj1TQIpRDBbLay3Mo4euUZmV1Q/Eoo9Pi39hikPNcUu xV2KvUfyE/Nb/AvmVrfUXP8Ah3VSsd/1PoutfTuFA/lrR6dV9wMUF9qwTwXEEdxBIssEyrJFKhDK yMKqykbEEHbFC/FXYq7FXYq7FXzz/wA5Ofm7DaWMvkbRZw17cgDW5kNfShO4t6/zybcvBdu+KQ+X MUuxV2Kph5fvbGx13Tr2/ga5srW5hmubdCFaSONwzICaj4gKYq+8PIv5m+TvO1mJ9DvVedVDT2Et EuYq/wA8dTt/lLVffFiynFXYq+arz/nE3UNS836rdvqsGneX57uSazjiRprj0pG5hOJ9NE48uIPI 9OmKbSD86v8AnHm28oeXbXXPLclze2lqOGsicq8i8j8M44KoCV+Fh229zioLwrFLsVZ95Q/PP8yv KsCWlhqhubCMcY7K9UXEagdApb94oHgrAYrTK7r/AJyy/M6aD047fS7Z6f38VvKX+6SaRP8AhcUU 8y81ed/Nfmu7F15g1Oa/kWvppIQI0r19OJQsaf7FcUpHirsVe3/848/nVpXlAv5b1yFINJvp/VTV EX4opmAX9/8AzRkKBUfZ+XRQQ+uIZopokmhdZIZFDxyIQysrCoZSNiCMUMU/NTzZrnlPyTfa7o2n pqN1acS8cjMEjjJo0zKvxOE2qoI23rtir4i83+evNXm/UTf6/fyXcgJ9GI/DDED+zFGtFUfRU964 skgxV2KuxV2KuxV63+T/AOf+s+SAmk6oj6n5bJ+GDl++tq9TAzbFf8g7eFN6qCH1b5R/MDyf5utF uNB1OG7PENJbcuNxHXtJC1HX50p4HFDIcVdiqE1TV9K0mze91S8hsbSMVee4dY0H+yYgYq+efzW/ 5yjg9GfR/InJncGObXZFKha7H6tGwqT/AJbUp2HfFNPmqaaaeZ5pnaWaVi8srkszMxqzMx3JJ6nF KzFXYq7FXYqiLDUL/TryK9sLiS1u4W5Q3ELFHUjuGUgjFX1p/wA46fmr5386Je2Gu20dzbabGp/T a/u3Z2NFidAODuQC3JeNANxvigvbcUOxVKfNmu6PoPlvUdW1kr+jbWBmuEcBhICOIi4nZjITxA71 xV+eup3UF3qN1dW9slnBPM8sVpGSUiR2LLGpbeig0GLJDYq7FXYq7FU08ueWNf8AMmpx6ZodlLfX svSOIbKP5nY0VFHdmIGKteY/LeteW9YuNH1q1a0v7Y0kiahBB6MrCoZWHQjbFWa/kt+UN/5/1znO Hg8u2LA6jdgU5nYi3jP87Dqf2Rv4AqCX2zpunWOmafb6fYQrb2VpGsNvAgoqIgoqj6MUKlzbwXNv LbXEaywTo0c0TCqsjjiykeBBxV8Hfm5+X1x5G86Xek0Y6dL/AKRpcx3520hPEE92Qgo3uK98WQYX irsVdirsVdirsVVLe4nt5knt5HhmjPKOWNirKfEMKEYqzTS/zt/NbTI1jtfMt2yJ9kXBS66dv9IW XbFaRV5/zkB+cF2nCXzJMoIpWGG2gP3xRIcVpher67res3H1nV7+41C43pLdSvMwr1oXJpiqBxV2 KuxV2KuxV2Kq9jZXd/ewWVnE093dSLDbwoKs8jkKqj3JOKvvX8rfIdr5H8m2WiRcXugPW1CdR/eX MgHM/IfZX2AxYstxV2KsH/N78tX/ADA8srpMepyadLBL9YioA0EkighROuzECppQ7HehxV8Z+d/y 782+StQ+p6/ZNAHP7i7T47eYDvHINj8jQjuMWVsy/Ib8nIvP2oXt3q5lh8v2CmN5IWCSSXLr8CIx DD4FPNtvAd8UEvQ9X/5w7tWcto/mR403pDeW4kPt+8jeP/iGK2+bb+zlsr65s5f722leGT/WjYqf xGKW9NazXULVr1edmJozcpUisQYcxVfi3WvTFX6GeXfLHl3y5YLY6Fp8Gn2mxKQKAWP8zt9pz7sS cWKRfmT+Vnlnz/pa2uqoYbyCpstShp60JJ3ArsyNTdW2+nfFU98seWdG8s6Ja6Lo8At7G0Xiij7T H9p3P7Tsd2OKppirsVeY/n/+Ww85+S5JbOLnrmjh7rT+I+KRafvoP+eirUf5QGKviTFk9B/Ln8kf O3nh0ntLf6ho5Px6rdArGR/xUv2pT/q7eJGK2rfm9+S+tfl9eRzB21DQbmi2+pBOPGSm8cqgtwbq V3oR9OKAXnGKXYq7FXYq7FXYq7FXYq7FXYqnXlHyjr3mzW4NG0S2a4u5jVj0SKOoDSyN+yi13P8A HFXqPn7/AJxc836Dai+0Cb/EFqiKbmCNPTukYD4ykVW9Ra9OJ5ex64ot4tJHJHI0cilJEJV0YEMG BoQQehGKX0H/AM4qflsL3UZvO+oxVtrEtb6QrjZrgj95MK/77U8V/wAonuuKC+pMUPLfMH/OSX5Y aJf3enzXF3c3llLJBcQwWzgiWJijpWX0hswI60xWmH6j/wA5heXI+X6N8vXlz14/WJorevhXgLim KaZb+Sv513H5jXusW9zpsemnT0gkt0jlMpdZC6vyJCfZKrSg74oek6vo2lazp8unaraRXtjOKS28 yh0P0HuOxxVC+VvKuh+VtFh0bRLf6tp8BdkjqWNXYsxZmJZjv1JxVNgQRUbg4q+UPNv/ADjR+Yes +d9cvtPSzttMvb+e4tZrm4p+7mlLj4Y1kcU5dxim0bpv/OHmuOVOp+Y7a3H7YtoJJ/oBdoP1Yrb6 bsLZ7WxtrZ5PVeCJI2lIpzKKFLUqaVpXFCvirsVdirsVdirzKz/5x6/LuLzhf+Zbm1N693N9Yg06 an1SF23ciMD46vU0bYeGKvTI40jRY41CIgCoiigAGwAAxVC6rpOm6vp0+m6nbR3djcoY57eUclZT /nse2Kvk384v+cc9R8qx3OveXXN95djrLcQSEfWLRPcn+9QfzD4h3HfFNvE8UuxV2KuxV2KuxV2K uxVm35Y/lP5k/MDUXh03hb6fbMov9Rl3SINuAEBDO5ANFH0kYrb7J/L38tvLPkTSPqGjQ1mkAN5f yUM87ju7Door8KjYYsWVYqwL8xfyW8k+eY3lvrb6nq9P3eq2oCTbdBIPsyj/AFt/AjFWWeXNA07y 9oVjommp6dlYRLDCvcherN4szVZj4nFUxxV8Ifnlpw0/82vM0AULzu/rNBT/AI+o1nrt4+rXFkGC 4q9o/wCcVNetdM/MC9gvLiO3tr3TpEDysEX1I5Y3Xdtvs8sUF9fxSxTRiSJ1kjb7LqQwPbYjFDzL 8/vzOHkryg0FjLx1/Vw0Gn0PxRJSks/+wBov+UR4HFXzf+Wf57+cfJDx2vqHVNCB+PTblieA7+hJ uYzv03X274pp9Y/l/wDmn5P89WXraNdcbxF5XOmz0S5i+aVPJf8AKUkfTihl2KuxV2KuxV2KuxV2 KuxV2KuxV4j/AM5W+bv0X5HttAgk43WuTgSgGh+rW5Dv03+KTgPcVxSHyJil2KuxV2KuxV2KuxV2 KvZf+cWvN36G/MJtImfjaa/CYKHYfWIayQn7uaD3bFBfYmKFO5ube2t5Lm5kWG3hUyTTSEKiIoqz Mx2AAxV8e/nT+fGqeZ9eitfLd1NY6FpUwktZomMclxPGdrgkUIUfsL9J32CkB67+Sn/OQVh5rhj0 TzLJHZeY41Pp3BpHBdqo6rU0WWn2l6HqvgFSFH8xf+co/LOhSS6f5YiXXNRSqtdcitkjDwcfFN/s KL/lYrT5g84+btZ83eYLnXdYaNr654h/SQRoFjUIqqo8FHck4pSTFXYqmGk+YNd0eYTaTqNzp8oN edtM8Jr78CMVV/MvmvzF5nvo7/Xr6TULuKJYI5peNRGhJVfhAHViffFUoxVkv5c6D5h13zppeneX 55LTUpJgyX0LMjW6LvJNyWhARa/Pp3xUv0AtomhtooXlaZ40VGmenNyooWagAqepxYqmKuxV2Kux V2KuxV2KuxV2Kvi//nJnWtU1L8zbmO5t5rey0+NbPT/WRkWRU+OSROQAIaRzuOopikPJsUuxVl/5 TeUf8WfmDo+junO0eYTXwPT6vB+8lB/1lXiPc4qX3Pc+V/LN0a3OkWU5rWslvE+/SvxKcWKnH5O8 oxOHi0PT0cdGW1hB+8Lir5v/AOctPJcNhquk+ZbKFYra9jNldLGAqiWH4ozQCnxRkj/Y4pD59xS7 FUdol3qVnrNjeaYGbUbaeOazEalm9WNwyUVdz8Q7Yq/RDR786jpNlftBJbNdwRztbTKUljMiBijq wBDLWhBxYvmT/nJz819Zn1WfyNYxTWGm23E6jK4KNdkgMoX/AIpX/hj7AYpD58xS7FXYq7FXYq7F XYq7FXYq+lP+cRZ/J0barEZaebp6cY5QBWzQA0gNd/j3kHXp2GKC+lcUOxV2KuxV2KuxV2KuxV2K uxVCapo+k6taNZ6pZwX1q+zQXEayof8AYuCMVeR+bv8AnFjyDq/qTaLJNoN21SqxH17atO8Uh5Df +Vxim3ifm7/nGv8AMvQOc1raprdku4msCWkpSvxQNxkr/qhsVt6T/wA4meR7myXW/Muo2zwXJYaZ axyoUkULxlnqrUO5MY6djipfRWKHYqwf86vKP+Kfy31fT4053kEf1yyA6+tb/GAP9deSfTir5E8o /kz+Y/mrhJpmjyx2b7i+u/8AR4KUryDSULj/AFA2LK3tnlH/AJxE0mDhP5r1Z72QULWVgPSir4GZ wZGHyVMUW9p8r+QvJ3laERaBpNvYmnFpkTlMwAp8cz8pG+lsUJ9irCvzQ/Kry9+YGj/Vr5fq+pW4 J0/U4wDJEx/Zb+eMn7S/dQ74q+IfNXlvUPLPmG+0HUTG15YSelM0Lh4yaBgVb5Eddx0O+LJKcVdi raqzMFUEsTQAbkk4qz7y5+RH5p6/Ek9rocttauKrPestqCD0ISUrIQfELitp5c/84u/mzFCZI7W0 uHAqIo7pAxP8v7zgtfpxRbz7zL5M81eWLgQa/pdxpzsSI2mQiN6deEgqj/7EnFKS4q7FUbousajo uq2uq6bM1vfWUiy28y9Qy/rB6Edxir61tf8AnKf8vY/LFjf35nfWZogbvSbWIs0cqni37yT04+JI qvxVp2xRTG9F/wCcrLrWfPGkaZHpMOn6FeXSW1zNNI0s9Jf3aNyXgiAOyk7Nt3xWn0Xih2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVI/PPmeHyt5Q1bX5QGGn27SRoejSn4YkPT7UjKM Vfnze3lzfXk97dSGW6upHmnlbq0kjFmY/MnFkoYqi9L0u/1XUbbTdPga5vruRYreBBVmdjQDFX2X +UX5EeX/ACTaQ3+oRx6l5nYBpLxwGjt2/ktgw+Gn8/2j7DbFi9TxV2KoTVdJ0zVrCXT9TtYryynB WW3mUOjA+x/Xir5J/Pf8iT5Nb9P6AHl8tzPxmhYlns3Y/CpY7tG3RWO4Ox7EqQXi+KXYq7FVysyM GUlWU1VhsQR3GKv0E/LnzOvmjyNouu1DS3lshuadBOn7uYfRIjYsWR4q7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq+PvPv5//AJsab548wabp+ti3sbHUbu1tYBa2b8Y4JmjUcnhZjsvc4ppi fm787fzD826K+i61fxzafI6SSRxwRRFjGarVkUGld6YrTA8UuxV9H/8AOJHkiCaXUvON3GGa3b6h ppYfZcqHnkFe/FlUH3bFBfTWKHYq7FXYqhNX0qw1fS7rS9QiE9lexPBcRN0ZHFD9PgcVfnz5v8u3 HlvzRqmhTnlJp1zJAH/nRW+B/wDZJRsWST4q7FUz0Lyx5i1+5+raLptzqM37S28TScfdiooo9zir 7D/5x48pedfKnk640nzPbpbD6ybiwhEiSOiSqOaP6ZZR8a8up6nFi9TxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV+evn+R5fPfmSWQ1d9UvWY9Kk3Dk9MWSQYq7FXYq+2f+carWKH8ndFkQ fFcyXcsn+sLuWP8A4jGMWJeoYq7FXYq7FXYq+Lf+cnbWCD83NQeIANc29rLLT+f0gn/EUGKQ8oxS 7FX6KeU7e3t/LOlRwRJFH9UgPBFCipjUk0HjixTXFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq+SPMP/OMH5n3msahqETWEy3d1NOgNwwciWQsC3KMCu+++KbYL58/Jzzt5H0631HXYYFt Lmb6vG8EokpIVLgEAClVQ4ptg+KuxV9df84m+Y4b7yFd6ISBc6PdseFd/Ruf3iN/wYkH0YoL2/FD sVdirsVdir4N/OnzJD5i/M7XtSt3ElqJxbWzj7JjtkWEMvsxQt9OLIMIxV2Kv0E8j+cfJ2v6RbR+ XtWgv0t4UjMSNxmUIoHxwvSRfpGLFkuKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KvPfz78rP5j/ACv1e3hTnd2KjULYUqeVt8TgDxaLmo+eKvhjFk7FWZ/lN+Y135C83QauitNYSj6v qdqp3kt2IJKg0HNCOS1+XQ4qX3ToutaXrel2+qaXcJdWF0gkgnjNQQf1EdCDuDixRuKuxV2KvIf+ cgfzgtfKOgzaHpc4bzNqUZjUIQTawuKNM9PssVNIx4/F23VD40xZOxV2Kq1pd3dncR3NpNJb3MR5 RTxMUdT4qykEYq+5vyOfzVN+W+l3vma+lv8AUL4NcxPPQyJbvT0VZgAXqo51ap+LrixZ7irsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeOfnF/zkJo3lFZ9F0L09T8x0KS1+K3tSdj6pB+J x/vsf7KnQq0+O5HaSRpGADOSxCgKtSa7KoAA9hiyW4q7FWZfl3+a/m/yHdtJo9wJLKZg1zptxV7e Q/zcQQUan7SkHxqMVp9CeXP+ctfJF5Ci65YXelXW3MxgXMHzDKVk/wCExRSeXH/OT35RxRF0v7md h0jjtZQx/wCDCL+OKKeZ+ef+ctdSvIJLPydp505XBH6SveDzgH+SFeUan3Zm+WKaeA39/e6heTXt 9O9zd3DF555WLu7HqWY7nFKHxV2KrmVkYqwKsOoIoRirIvy68pTebfOuk6AgPp3c6/WnH7NunxzN 9EamnvipfoFBBDbwR28CCOGFVjijXYKqiigDwAxYr8VdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVUru2jurWa1kLLHPG0TtGzI4VwVPF1IZTvsRuMVfCH5s/ltqfkLzVLp1wWnsLnlNpl8R/f Qk9GP+/EJo4+noRiyDCsVdirsVdirsVdirsVdirsVe2/84//AJIT+Z76HzL5gtyvlu2flbQPt9cl Q7Ch6wqR8R/a+z40UEvpXzb+WnkfzbEV13SYLmalFu1HpXCjtSaPi9B4E0xQxr8tfyI8veQvMt/r Wn3k12LmAW9pDcqpe3Vn5SfvFpz5cVA+EUAPWuKvTMVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVYp+Zn5e6V578rz6PegR3ArLp95SrQTgUVv8AVPRh3GKvjbSPyf8APeqecrrylBp5 TUbGThfzSVW3hXqJXkp9hl+JKbsOgOLK30hp/wDzi55Ah8oPo956lxq8tHfXVPCVJQNvSSpUR7/Y Na9zWhCxt8+/mN+R3nbyRJJPPbnUdFUkpq1qpaML1rMgq0J/1vh8CcWVvPMVdirsVdirsVdir7r/ ACQ882vm/wDL+wuUVIr2wUWN/bxgKqSwqAGVRTisiUYbUHTtixZ9irsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVaEaKzOFAd6cmA3NOlTireKsF/PHXP0N+VXmK6Visk1t9Tj I68rthBt8hITir4QxZOxV7x+XP8AzjCPNXlPTvMV7r7WI1GN5Fso7UOVUSMqH1TKteSry+x3xRb0 Kw/5xK/L+C2mW6vr+8uZEZIpWeONI2IIVxGigkqd6FqHFbfK/mPQdQ8v67faLqKene2EzQzDsSp2 ZfFWFGU9wcUoOzs7y9uY7SzgkubqY8YoIUaSR28FVQST8sVfVH/ON/5V+fvKV3d6vrTR2FhqMAjf SGPOdnVqxyvxPGMqC21SdzUDFBe94odirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirCfzd/Lu68/eVV0O31IaYVuUuXkaL1hII1cCMgOnEcnDV36Yq+cdc/wCcVfzNsC7a ebLVoxuggm9KQ/NZxGoP+yOKbYBrP5Z/mDozFdS8vX8Kg09UQPJFX2kjDIfvxTb7w8r6Omi+W9K0 hAAun2kFrt4xRqhP0kYsUzxV5H+a3/OP9j5881WGtrf/AKNAi9HVuCc5JlT+6MdSFDUJUlu1PDFb Zl5H/LHyX5KtRFoenqlwRxlv5aSXUn+tKRWn+StB7YqyrFXYq7FXYq7FXYq//9k= + + + + 1 + False + False + + 25.000000 + 25.000000 + Points + + + + Black + + + + + + Default Swatch Group + 0 + + + + application/pdf + + + gears + + + proof:pdf + uuid:d4264966-bb79-a443-8341-b631b0b9c53e + uuid:93f2449e-88c5-e040-a90e-e4d65a03e3ce + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 5 0 obj <>/Resources<>/Properties<>>>/TrimBox[0.0 0.0 25.0 25.0]/Type/Page>> endobj 6 0 obj <>stream +H‰lVÍn7 ¼ïSì ¬"’’(]›½4‡ ‡ž #m�8’žúö�!e{¿ pb/W+Š?3C½ûå÷?};ß}x_Ï~|_�zjç¿ ÿ¿}:~;ÿÆ+þÈùùx÷ó¯õüóŸã+¬|çeù§hqév>}‰¯¿—”i†ÇËŠ©�RÚ’#?ÛìEú8÷ŽQFØ—ŸŽûÛûç�žî‡¼œÌŸX�ui©º—aqò,;[ÑÕiÖZŒ°–9ûFÍïô|>¼4Õ³–ÞV/ û°m4XøÒÖ’‰8uÚ©¥×Žg« Š4øC¡”Q·ôæ y¬¡ámv…5|„54üß™:ž½1<~íEÅ"ºŠx&üpO‹ä¤Á‡Ï‡¢'Xc4¼¯"ˆ•Y|6g•¬ +žÛÊ*Ó�†tý¿�_‡ùæèºŸpÝÎF¿ ìz ûºçóžîÅ:ø®Ãu/Ü>ÖﺗöºW=Ì·†\÷N]lâØMLŸ·óS•·þ_7tÌ´oйPu=@.P>qþt_Y½Öá«•6ÂW:eéTÒî+mä‹¥§5ù”Oßëëûû–ì-ûóz£ñ·hþ:þ8>Þ-^|¢éVÀëñ@h]‹áÈŒpzÉŠ3}-cB4�ïd¾ZæèAMgMØÚJ·(߃Ee£‘„s4›cÏŠnÑQ:}€µ.öiF·N ›ÜôÌAí>ƒÆÕ"MóÎ5ï�’ §"¶:ˆ¤ÚBZŠK%XCo€c_ii1­ºeÈm!‚&Ï3Sªi2œOœ <Ü]6mÆëiXÔA„·îQÂÖ÷Þ³§<¬VßøéŒÄ—'Mï;‚è‰,âPK«EM;ÚÊìçˆþ;ꈌCVI)€fâlè”4’.ܸ³Ü}¶mkPF‡^H5iÚЗƒÅ¯†¨ˆÙ›¦ð ¡M견ÀKI"4��êA9V–Œà±T­®µm’Ì€±%Aqd \J_i‹½ÚhR‚V8[’º0d +{:®“k.Ñ� +g5…B¢Á#�VµÀ¸?ÐÐÙ>ŒKM ž[/ŒÒDÝaÈ%gÒˆ�ô„ãxp!öõ�vú¦°ó/*²�É% ý­dˆ-²‰…Ò@ã÷Ï�¿¨ð÷äV¸ +EFÛØüÆnæbcùc˜_©ÛlL£ÄøØC»Z@Å£ŠcÅéÜ™Ÿ%l‘û à|-êÔ”Ö£Æ�Ütʪj'ý‡é™Ad /Ó›Â�@i0¼1mí9Ù†„5û®?5Õã@¢-J‰UÞˆ;z«FkJî ÄS=VÐÝ�ëba=-Ü!� ”л±ä¡ãJ1aér.ä°èF઼­¨x’_Q¶4 rœ +&ãwLSº©n‰tC´ðš$1”&.=«§)‹‘YŽP qoyƒ²�Q†T ¼Ò‘£Ø•ÀxÑ!±uó»aư°k›=�f1682û~6Þ²´�²³�kl'”OBÈvàË%A”&�Ë9~fPÂk^ [�`åy›§š:ÑgP­½èF]Qıö@õ)©3!-&óÌw’Ã^(sNN¡ê¼‰ÄqÙ"1ëcuª‡±ó£­lsŽèZ (¸ŒóZ%ŽëŠL¢PûUòŽ•KÓÚˆ(‡[‚YkðO$MDž8�Ì´ Iã1ß…'»ú€{ûÇã?²(<ø endstream endobj 9 0 obj <> endobj 8 0 obj <> endobj 7 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 23.0.6 %%For: (Leo Natan \(Wix\)) () %%Title: (mechanical-gears-.eps) %%CreationDate: 8/22/19 07:46 %%Canvassize: 16383 %%BoundingBox: -8 -8 18 16 %%HiResBoundingBox: -7.94902038574219 -7.54520848906577 17.0509796142578 15.8572202078167 %%DocumentProcessColors: Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 637 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKProcessColor: 1 1 1 1 ([Registration]) %AI3_Cropmarks: -8 -8 17 17 %AI3_TemplateBox: 4.5 4.5 4.5 4.5 %AI3_TileBox: -283.5 -351.5 292.5 382.5 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 2 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -38.9138487575465 50.1096822115132 9.14804902839473 1605 1001 26 0 0 140 74 0 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 7 %%PageOrigin:0 0 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 12 0 obj <>stream +%%BoundingBox: -8 -8 18 16 %%HiResBoundingBox: -7.94902038574219 -7.54520848906577 17.0509796142578 15.8572202078167 %AI7_Thumbnail: 128 120 8 %%BeginData: 17120 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD21FFA827202727272027272720272727A8FD71FFAFF827F827F8 %27F827F827F827F8A8FD71FFA8272727F8272727F8272727F827A8FD71FF %A8F827F827F827F827F827F827F8A8FD71FFA82727272027272720272727 %2027A8FD63FF537DFD0CFFA8F827F827F827F827F827F827F8A8FD0CFF7D %52A8FD53FF52F827A8FD0BFFA827F8272727F8272727F8272727A8FD0BFF %A8272752A8FD50FFA827F827F827A8FD0BFFF827F827F827F827F827F827 %F8A8FD0AFFA827F827F8277DFD4EFF8427272720272752FD08FFA8A85227 %20272727202727272027272752A8A8FD08FF522027272720277DFD4CFF7D %27F827F827F827F852FD04FFA8A85227F827F827F827F827F827F827F827 %F827F827527DA8FD04FF7DF827F827F827F82752FD4AFF52272727F82727 %27F827277DFFFF7D27F8272727F8272727F8272727F8272727F8272727F8 %27272752AFFF7DF8272727F8272727F82752FD48FF5227F827F827F827F8 %27F827F852F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F852F827F827F827F827F827F82727A8FD45FF2727202727272027 %272720272727202727272027272720272727202727272027272720272727 %2027272720272727202727272027272720FD0427A8FD42FFA8F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F8A8FD42FF %59F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %52A8FD43FF52F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827A8FD45FF52272720272727202727272027272720272727202727 %272027272720272727202727272027272720272727202727272027272720 %2727272027A8FD46FFA827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F8277DFD25FF275252A8A8FD1EFF7D272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272727F82727 %27F8272727F8272727F8277DFD1CFFA952FD07FFA8272727F82727527DFD %1CFF7D27F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F82752FD1BFFA87D %F82752FD06FF7DF827F827F827F87DFD1DFF272720272727202727272027 %272720272727202727272027272720272727202727272027272720272727 %202727272027272720A8FD1AFF7D2727272027A8FD05FF53272727202727 %27A8FD1CFF2727F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F8FD18 %FFA82727F827F827F852FFFFA8A87D52F827F827F82727FD1CFF5227F827 %2727F8272727F8272727F8272727F8272727F827272720272727F8272727 %F8272727F8272727F8272727F8272727F827272752FD17FF52272727F827 %2727F8522727F8272727F8272727F852FD1BFF7D27F827F827F827F827F8 %27F827F827F827F827F827F8525284FD06A85252F827F827F827F827F827 %F827F827F827F827F827F8277DFD17FF2727F827F827F827F827F827F827 %F827F827F827277DFD05FFA827A8FD12FF52272720272727202727272027 %272720272727202752A8FD0BFFAF53272727202727272027272720272727 %202727272052FD17FFA82727202727272027272720272727202727272027 %2752A8FFFFA8202727FD11FF7EF827F827F827F827F827F827F827F827F8 %27F852A8FD0FFFA87DF827F827F827F827F827F827F827F827F827F87DFD %17FF52F827F827F827F827F827F827F827F827F827F827F827597DF827F8 %2752FD07FFA87DA8FD06FF5227F8272727F8272727F8272727F8272727F8 %84FD13FFA82727F8272727F8272727F8272727F8FD0427FD06FFA97D7EFD %0DFFA8FD0427F8272727F8272727F8272727F8272727F8272727F8272727 %F82759FD06FFF827F827277D7DA87D27F827F827F827F827F827F827F827 %F827F8A8FD15FFA82727F827F827F827F827F827F827F827F82753A87D7D %2727F827F8FD0CFFA8F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F8277DFD04FFA82727272027272720272727202727 %272027272720272727202727A8FD18FFFD04272027272720272727202727 %2720272727202727272027A8FD05FF7D53A8FFFFFF272720272727202727 %27202727272027272720272727202727272027272720272727A8FFFFFFA8 %F827F827F827F827F827F827F827F827F827F827F827F827F8A8FD19FFA8 %F827F827F827F827F827F827F827F827F827F827F827F827F87DFD04FFA8 %27F827277D2827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F82752FD04FF7D27F8272727F8272727F8272727F82727 %27F8272727F827277DFD1BFF7DF8272727F8272727F8272727F8272727F8 %272727F827272752FD04FFA82727F8272727F8272727F8272727F8272752 %52A87D7D52272727F8272727F8272727F82727277DFD05FF7DF827F827F8 %27F827F827F827F827F827F827F827F827F827A8FD1CFF52F827F827F827 %F827F827F827F827F827F827F827F827F852FD04FF2727F827F827F827F8 %27F827F827F82752A8FD06FFA87D2727F827F827F827F827F8277EFD06FF %5227202727272027272720272727202727272027272720277DFD1DFFA827 %27272027272720272727202727272027272720FD0427FFFFFFA827272720 %27272720272727202727277DFD0BFF5227272720272727202727FD06FFA8 %27F827F827F827F827F827F827F827F827F827F827F82727FD1FFF2727F8 %27F827F827F827F827F827F827F827F827F827F827A8FFFF7DF827F827F8 %27F827F827F827F8277DFD0DFF5227F827F827F827F8277DFD05FFA8F827 %2727F8272727F8272727F8272727F8272727F827277DFD1FFF84F8272727 %F8272727F8272727F8272727F8272727F82727A8FFFF2727F8272727F827 %2727F82727277DFD0FFFFD0427F8272727F852FD05FF7D27F827F827F827 %F827F827F827F827F827F827F827F8277EFD1FFFA827F827F827F827F827 %F827F827F827F827F827F827F8277DFFA87D2727F827F827F827F827F827 %27FD10FFA8F827F827F827F827F8FD05FF7D202727272027272720272727 %2027272720272727202727FD21FF28272727202727272027272720272727 %202727272027277DFD04FFA87D272720272727202727A8FD11FF52272720 %27272720277DFD04A85227F827F827F827F827F827F827F827F827F827F8 %27F852FD21FF52F827F827F827F827F827F827F827F827F827F827F82727 %FD06FF52F827F827F827F827A8FD11FF7D27F827F827F827F827F827F8FD %0427F8272727F8272727F8272727F8272727F827272752FD21FF7D27F827 %2727F8272727F8272727F8272727F8272727F827A8FD05FFFD0427F8FD04 %27FD12FFA8F8272727F8272727F8272727F82727F827F827F827F827F827 %F827F827F827F827F827F87DFD21FF7DF827F827F827F827F827F827F827 %F827F827F827F82727A8FD04FFA827F827F827F827F852FD12FFA827F827 %F827F827F827F827F827FFFFFF7D7D5252FD042720272727202727272027 %272752FD21FF7D2720272727202727272027272720272752527D7DA8FD08 %FFFD04272027272752FD12FFA820272727202727272027272720FD08FF27 %27F827F827F827F827F827F827F852FD21FF7DF827F827F827F827F827F8 %27F82727FD0DFFA827F827F827F827F852FD12FF7D27F827F827F827F827 %F827F827FD08FF7DF8272727F8272727F8272727F82752FD21FF52272727 %F8272727F8272727F8272752FD0BFFA853522727F8272727F82727FD12FF %7D2727F8272727F8272727F82727FD08FF5227F827F827F827F827F827F8 %27F827A8FD20FF52F827F827F827F827F827F827F82752FD09FF7D27F827 %F827F827F827F827F8277DFD11FF2727F827F827F827F827F827F827FD08 %FF7D202727272027272720272727202727A8FD20FFFD0427202727272027 %27272027277DFD09FFA92727202727272027272720272752FD10FF7D2727 %272027272720277DA87DA87DFD08FF7D27F827F827F827F827F827F827F8 %2753FD1FFF7D27F827F827F827F827F827F827F8277DFD0AFF52F827F827 %F827F827F827F827F87DFD0EFFA827F827F827F827F82752FD0EFF2727F8 %272727F8272727F8272727F852FD1FFF522727F8272727F8272727F82727 %27F8A8FD0AFF7D272727F8272727F8272727F82727A8FD0DFF522727F827 %2727F82727A8FD0DFFA852F827F827F827F827F827F827F827F884FD1DFF %A8F827F827F827F827F827F827F827F827A8FD0AFFA8F827F827F827F827 %F827F827F827F87DFD0AFFA852F827F827F827F827F827A8FD0EFF522720 %2727272027272720272727202727FD1DFF52272727202727272027272720 %27272752FD0CFF5227272027272720272727202727272052A8FD07FF7D27 %202727272027272720277DFD0FFFA8F827F827F827F827F827F827F827F8 %2753FD1BFF7D27F827F827F827F827F827F827F827F87DFD0CFF7D27F852 %7D7DF827F827F827F827F827F8272752537D5252F827F827F827F827F827 %F827F852FD0EFFA828272727F8272727F8272727F8272727F827A8FD19FF %A8272727F8272727F8272727F8272727F82727A8FD0CFF52A8FFFFFF5327 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %52FD0BFFA853F827F827F827F827F827F827F827F827F827F827A8FD17FF %A827F827F827F827F827F827F827F827F827F827F852A8FD0FFFA827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %A8FD08FF7D2727272027272720272727202727272027272720272727A8FD %15FFA8522027272720272727202727272027272720272727202753FD0FFF %A85220272727202727272027272720272727202727272027272720272727 %2027277DFD06FFA82727F827F827F827F827F827F827F827F827F827F827 %F827F8277DFD13FF7D27F827F827F827F827F827F827F827F827F827F827 %F827F827277DA8FD0DFF5227F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F87DFD06FFA8F8272727F8272727F8272727F827 %2727F8272727F8272727F827272752FD11FF5327F8272727F8272727F827 %2727F8272727F8272727F8272727F827277DFD0CFFA8272727F8272727F8 %272727F8272727F8272727F8FD0727F8272752FD08FF52F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F87DA8FD0BFFA87D27 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827A8 %FD0CFF52F827F827F827F827F827F827F827F827F827F827F82727A8A827 %F827F852FD09FFA827272720272727202727272027272720272727202727 %272027272720272727527DA8FFA8FFFFFF847D5227202727272027272720 %2727272027272720272727202727272027272720277DFD0CFF7D20272727 %202727272027272720272727202727272052A8FD04FF522052FD0BFF5227 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F8272727F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F82727FD0DFF7D27F827F827F827277E52522127F827 %F827F827F852FD06FFA852A8FD0CFF20272727F8272727F8272727F82727 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F82727A8FD0EFF %A852F8272727F8A8FD04FFA852F8272727F82752FD15FF7DF827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F853FD11FF7D2727F852FD06FF5227F827F827F827A8FD15FF522727 %202727272027272720272727202727272027272720272727202727272027 %272720272727202727272027272720272727202727272027272720272727 %202727272027A8FD13FF5227A8FD06FF7D20272727202727A8FD15FF7D27 %F827F827F827F8272727F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F8272727F827 %F827F827F82759FD0DFFA8A8FD06FFA8FD07FF7D27F827F827F827A8FD16 %FF52272727F827275284FF5227F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F827272728FFA8 %52F8272727F82727FD07FFA8A87D7D5252272727FD0EFFA8275253A8A8AF %FD18FFA8F827F827F87DFD04FF5227F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F82728FD04 %FF7E2727F827F8A8FD06FF5227F827F827F827F827A8FD09FFA8FD23FF7D %272752FD07FF522727272027272720272727202727272027272720272727 %20272727202727272027272720272727202752FD07FF7D272052FD07FF84 %272720272727202727A8FD08FFA8527DFD22FFA852A8FD09FF7D27F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F82752FD09FFA852A8FD07FF7D27F827F827F827F8277DFD08FF52 %F82752A8FD2DFFA8522727F8272727F8272727F8272727F8272727F82727 %27F8272727F8272727F8272727F852A8FD14FFA8F8272727F8272727F87D %FD07FFA82727F827277DFD2EFF52F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827A8FD15FFA827F827F827F827 %F82727A8A8FD05FF2127F827F827F85284FD2CFF27272027272720272727 %202727272027272720272727202727272027272720FD0427FD0CFF7D52FD %09FFFD04272027272720FD0427597DFF5227272720272727202753FD2AFF %7D27F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F8277DFD0AFF7DF82752FD06FFA85227F827F827F827F827F827 %F827F827F827F827F827F827F827F827A8FD29FF7DF8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F8272727F8272752FD09FF %A82727F82752FFFFFFA852F8272727F8272727F8272727F8272727F82727 %27F8272727F827272753FD2AFF2727F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F8A8FD07FFA8F827F827F8 %2727A85227F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F82727FD2AFF7D27202727272027272720FD0427FFA8A87DA87DA8A8FF %522720272727202727272027272759FD07FFFD0427202727272027272720 %2727272027272720272727202727272027272720272727202727A8FD2AFF %52F827F827F827F827F827F827F87DFD09FF7EF827F827F827F827F827F8 %27F827A8FD05FF2727F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F87DFD2AFFA8F8272727F8272727F8 %272727F827A8FD09FFA8272727F8272727F8272727F82727A8FD04FFFD04 %27F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8 %272727F827272752FD2AFFA852F827F827F827F827F827F82727FD0BFF52 %27F827F827F827F827F827F8527DFFFFFFA827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F82752 %FD2CFF7D522027272720272727207EFD0BFFA8272720272727202727527D %FD07FFA85227272027272720272727202727272027272720272727202727 %2720272727202727272027272720277DFD2DFFA85227F827F827F827A8FD %0BFFA827F827F827F82752A8FD0AFFA852F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827A8FD04 %FFA853FD29FFA85227F82752FD0DFF5227272752A8FD0FFF7D2727F82727 %27F8272727F8272727F8272727527D5252FD0427F8272727F8272727F827 %2727F852FFA87D5227277DFD2AFFA87D2784FD0DFFA8277DA8FD11FFA827 %F827F827F827F827F827F827F82752A8A8FD05FFA87D2727F827F827F827 %F827F827F827F827F827F827F853FD50FF7D272720272727202727272027 %277DA8FD0BFF7D27272720272727202727272027272720FD0427FD4FFFA8 %F827F827F827F827F827F827F87DFD0EFF7D27F827F827F827F827F827F8 %27F827F827F8277DFD4EFF7D27F8272727F8272727F82727A8FD10FFA827 %2727F8272727F8272727F8272727F827277DFD4EFF52F827F827F827F827 %F827F87DFD12FF7D27F827F827F827F827F827F827F827F82727FD4DFFA8 %272720272727202727272052FD14FF7D2720272727202727272027272720 %272727A8FD46FF7DFD0427522727F827F827F827F827F8277EFD15FF2727 %F827F827F827F827F827F827F827F852FD46FF7D2727F8272727F8272727 %F8272727F82752FD16FF7D2727F8272727F8272727F8272727F82759FD46 %FF5327F827F827F827F827F827F827F827F87DFD16FF7D27F827F827F827 %F827F827F827527EA8FD47FF7D27272027272720272727202727272027A8 %FD17FF27272027272720272727207EFD4BFF5227F827F827F827F827F827 %F827F827F8FD18FF52F827F827F827F827F827A8FD4BFF7DF8272727F827 %2727F8272727F8272727FD18FF52272727F8272727F82727A8FD4BFF5227 %F827F827F827F827F827F827F82727FD18FF52F827F827F827F827F8277D %FD4BFF7D20272727202727272027272720272727A8FD17FFFD0427202727 %27202727A8FD4BFF2727F827F827F827F827F827F827F827F8A8FD16FFA8 %27F827F827F827F827F827A8FD4BFF84527D52535227F8272727F8272727 %F82753FD16FFA82727F8272727F8FD0427FD52FF5227F827F827F827F827 %F827A8FD15FF2827F827F827F827F827F827277DA8FD4FFFA82027272720 %2727272027277EFD14FFA827272720272727202727272027272752A8FD4D %FFA827F827F827F827F827F82727FD14FF52F827F827F827F827F827F827 %F827F827F8A8FD4DFF5227F8272727F8272727F82752FD12FF7D2727F827 %2727F8272727F8272727F8272727A8FD4DFF7EF827F827F827F827F827F8 %2752FD10FF7DF827F827F827F827F827F827F827F827F82752FD4FFF5220 %272727202727272027272752FD0EFF7D2027272720272727202727272027 %2727202727A8FD4EFF7DF827F827F827F827F827F827F827F87DA8FD09FF %7D52F827F827F827F827F827F827F827F827F827F852FD4EFF52F8272727 %F8272727F8272727F8272727F82752A8A8FFA8A87D7D2727F8272727F827 %2727F8272727F8272727F82727277DFD4CFFA827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F8272727F827F82727FD4CFFA82727272027272720272727202727272027 %272720272727202727272027272720272727202727272027272752FFA859 %2727277DFD4DFF2727F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F82727FD04FFA85252A8FD4EFF %21272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8A8FD56FFA8F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F82720A8FD58FF7D %272720FD0427522727202727272027272720272727202727272027272720 %272727202727A8FD5AFF52F827F82727A8FF7DF827F827F827F827F827F8 %27F827F827F827F827F827F827F827F8277DFD5AFFA852272752FD04FFA8 %2727F8272727F8272727F8272727F8272727F8272727F8272727F827A8FD %5AFF7D277DFD07FF7D27F827F827F827F827F827F827F827F827F827F827 %F827F827F87DFD5BFFA9FD09FF7D27272720272727202727272027272720 %27272720272727202727FD65FF52F827F827F827F827F8272752527D7E7D %F827F827F827F827F82752FD64FF2727F8272727F8272727A8FD06FF52F8 %272727F827272752FD64FFA827F827F827F827F82728FD07FF7D27F827F8 %27F852A8FD65FFA82727202727272027277DFD08FF5227272752A8FD67FF %7D27F827F827F827F8277DFD08FFA8F8527DFD6AFFA8A87D52FD0427F8FD %0AFFA8FD71FFA87D5252A8FD26FFFF %%EndData endstream endobj 13 0 obj <>stream +%AI12_CompressedDataxœÝ½çb2¹²(z_€wÛØ` tÎD眳 m›Ïp3kÎ�óì·J�›ŽÀܵ÷�µÆ´ºJ*U–JJ§Î¯ò¥v¿©äÙ•L¤ÓUiŒúêz’üš<èvÇÑŠ?e.³IZ,PШt ½é ouØé÷Ö“ (ð°ŽogŽ•~ò´1jô’Ï™»Îž³Ùd& O¯;£®Ï”ÖW£×i5ºùO¥¡óe0ÌˆÕÆÚIE†)Òr’×9^iôþj ‡�ÿÏh�•Xø­Ü÷Ú�Þg¹ÿŸõd^ÂÿÓðl¾ß¹T†ÎçbAædŠ¡X‰9@Ã/<Ç3”ÄI2%ð¢HFÉS²( 4Çð"Àâ Кaà5Q¢ Wû­ñ�Ò�«ý–2Vúݾ:\O–»�ÖwÄ¿Õ;]hñÓ%iÉV: ™·ò¸ÓmŸŽš +PI`Eü™}#¯ß Ÿ0,òß~à—+e4‚Þp$}åäáÈŽÈ ÿ/ót©|vÈdù^²:dµ?øi¨ßC“48>íÙµò3è™ a¸oÿWocÐÈÆH,<ȳ< ÿadþ²c´³¨¡üÕQþ^Ožö{ŠF†’:ºÒ¦‹ã(Jû«=¹wõ¦×AßüIÖèpÒo+]ý'ò~½Û Ã'ÿ£­¿Zƒë†ú©Œ`žûÝñˆ°¢d`:7þQpbh ÁÙ@é]÷oIó¬T�iæ]äEžø$OhJ$†¡ižf™¤\ 9‰B~‘X™Yà*ŠOÒE'AëG%EÎìmýÕº€�Ñä�s˜Õ3µóÙé­ë£ßöÔNÛši‘IJÚ2ÐŒÿ¡i™¡dFŽú‹Lþ𗀓£ü¢Q >)=�jÀµ•R…“+E­×®ôpÖ‡(„À{=`ÌnÿS{f~&Oàõñ@£ùþ r®vz3qJžHoçÝ1<ÚSûãÁAÈh:è꟟f¿Ûþ€ +™ü弡Ž:­®rõÏp¤ü�A6Z Ǧ&Ëêxø•¼î÷»XÇ#í}x¨ÿL~Åöÿ3pœ“zg=øðå…IoàÆò¤½ó?—ùŽxø¿È�ªX ÈWã¿áoWÝnçSm ¾:-¯Nz<7QÙŸÅèð­Ò{ªº� žæy+q^6‘°â�ðÀÙé61Ò`š¹¢)í‘æ3 ˜ÿGÿ¹~ô®÷Õpr!2i$ÒoEã;L'~ë´� õíûýÉñ)8²ž7’™ÿüt{ð8ŠIí4Ç#ÔÉ6-©jãÿs€okÕú‚ÀFUzZ&Y<ʘOñÏè”@|šYî ßþ‚¨oä + ÷>�MÿjtÇF[ü}èӮ¥5Ó{2t|û_J�OÓí·¾•vÊ-×þ»ãjvHNG0„ §dáã³·žÓôÏH :�‘Æßi4»JÆ�ÕÿM‚¾þWdQǦÿeŽÆáµÆÃQÿç¿«Éþ=>\6ÐoA›"•ÿu¹€¾üêÊÿ¤tøñ÷ÿ`kü_ƒa·Óúß®‹�å~¿ë?ÈfŠìXùiÉÉ(³<ùÎW#O&ó‹—J#`ÐÿDå?ÿía1|Ø8þî´G_QÆ¢7ü¯O“k&dxÿ‰¤rþÛÃbØG1# ² Iá“ö¥t>¿¢2³åÿ—€è«þXm)deí¿î€åúowáG5Úà"ÍÚyÆ~,¶õœDž²5Æ_(w逦“fnƒ,Ü$�½Ï1¦‚ÏûÌÖÙÛã +cIU%’¯�4ë.”hQN’?D8Îû�ÞÇ–!Ë�v+b ¨v†ƒn㟓¦-É0Kê¨Ùo¨í$†’7½N †f ׊iCüÎK—ºÚ!ËŸÞK¥{Ý¿Ôp’>œ÷‡ì,yJë`D\6�úã2¶C£³WJWi�Œ0Ü£�žü:�d£¡ªöŒG5cΘŒy]�$-\BM2IÕÀD˜ÈÄsžüîõ[ßýñ(ù©%`±©Àó,¶ŠÁªîy5Ñü4†ú<±‚1ƒF[ï�hhÐö SЇ¢ÿHTW—ÝÎÐE¯á oéÁÒA²4õ“—�áHÁu‰ˆã0‰JFÛˆm„”“ƒÆ@Q“ÃÎϸK² N=2 *"º¦)Ë¡c°š2¶f#µÑ QZÿ@ç;íäÐ$‹'t†}Ü’Ÿqœ4>W•¡¢þ¥$¯•ÿŒÈ2J£ÙévF:7’­f/ å¡mÖ¸2ñý´-ïà²÷Ûµ©á$ZÆýÇá\ +ÂýÚÕ¨aŠ�ö:'Q¦Ì»ã<Œ tɨÑk™‚EÒjt§>r7Á- “sænu‰üÒä;ߎ’vgƒFË$.Ƕ­7ZJ©÷iôÒ¿5z鮯~C"€Ë&ƒ±Œ(ˆAM÷,)áxIä|ÚÖ»ý¾jk—´µºÀKTAÛà@148ÆÚF¦Q‹ø„ý=Öw~*J·k±´ÿ<’˜È>�´/vYWj4)¦TòCÛ‹Ê”uW‡#µÿmx|¾ø ýÎ>>†ŠI +Y¢}ˆ��µhÍ í7…ØÒ6ƒmÛ—ÍÝø.ÔÇÝ®¡ôýað4Œ`Z‡í³B°¢Ñu’`C#:òº�«ÕýÞ¾Í}e:SHQœÈpéea½&l:ÓÛh‚ 3W•àI±öŸA_aV©4„‰)&)ò'öCLL;1¶†~“„AÃD"ÓÝhøÝ€çÚûn¦‚�U‡ +ŽIõŸËëXc{+cÜžóuØob”s¶œ.Ï$Òd®É?FùA´f×Öäªñ—ráZ•œ]7[M¬±~õÿÞï´'QÑšÉÈóΔ.¼ù¡L u^Ïðl J­÷{j£�áp²ÑkëË ¥ö©ÈÃÂP|‰,�»_rbÒh•öV8®0aªè¡jÜxÙËuÄn�Wëoâ`uì‹þ^’`4ßÃÔˆÖõ×ø§ÙktºÖÆBž~µÿwOÛr~Ô1VG¼+Ÿ×ÜÄb/ßÍçeRïZjö�ôŸöjÅòˆmý�ñÖŸaQ”áC≠Öòs&à¾âSÓùVURùCù›ØciœÛmÿÒ«%±Ç§*Ù nÈ.EAŸH»;°2¸þM­}ýÙG,éÔÚ[û)µÆÔ¯R™ýá~}|2 Þ¤u,0znçì}›Ú?ÜAÚH¹mau±ª¨åq-wr|—HW�RWÆóêw¡8ä÷7ÆŸ·\uQY;¨©ÏªTÚúW;ô­T]l�kÕ�Õ#~ãñ褻™.þV`hë}ÛÐ*ùÕ +Õ^yª˜s½DŸôÙØzà´Q•ûÃSí“NŽã¡ªrÕU¼ÿÝM�êsã‰Ó‰º—Zæ†ÌðÄèµ´—H3ã‡÷&ü°×¥ÚËU;Ø�á½ú’­žPEî*c'Ì›R�ws�ܳ¾ +¯ÑdšÎlH_n„ª…4‘v¡å/ØoÕé»úò;ºñAZi +—�<ã…4‘V‡Òí7Ö}NN—¾½‘n.,W–ú/¤êø½°”i.]>¤Ú¼ØÐRujgÓ©°¸$m|ÈÞH¹‡gª~]¾ðBšHêƒõôYçäÒk¬ÔÞbÿØéÊá1wâGÞõ¹Å"Ò,Èþ�îØ4?Z�¹þĬ®/mëHÏWV\sÊ]‹{]‚¸»Y³�¼Úõå¶yIÐN"]ãoÚŸEO¤¯ùëS_¤bñãj… M¤]haVSYu¸žz#=_¹û¯ã5/¤Ã•íÚ i"�Âþ•])+{^cÅY} ê2uê‰t¡þ).]þ0g^H©úËK� E�ì«°˜þî�Tü�6¨½µ÷[o¤{TiEɈ.¤€…x´¸¶£�õ!Ÿq ÍÎ)·õ¬!­=×H7©c1O#ÒÕ ¤ûJŸH*èäö²8p�õøé±áƒTX¿ÛõW?¤UêdõEv!,ÚƒßõÝ?êé¥'Ò«�Öé‘rÅR>HŸòÔÕ[ví‹×X�ö•Ó§ÇlÆéíJïÓéÕ×…®}-¤ÄŠih÷¨Û£Á¦7Òc6}SßÝÜòF:8\ðEzû¶·0"vßs¬gÔÝÎQÕéÉvííõâåÅéËÙ÷� )Á¢£ýóÀ·ë>HŸ%êeØÍ{#=ý3ø9“%ÖéÛAt²ïXÕôU.åƒôᆪu~=‘J§ù…ÔîK¾H× R°b–V¿‰o:Ò&›u Möñ¸±J�2+Û™}çH�©÷Õõ"]›°4o~éeúðíÐn©nU8ì/oþÑNÎ5Òú¬†´ü@8áš:¼ÙN!ÒA +c±k¥ƒ¼1ÖÊÈ…4·±¿ hHw裼)ÿµ6àNß Rvi½räDº„š¿Ñì!ZÊ=Vµ¤ô þ=L¹õ/ÿg½¬#]¿(¸È»ÐWÞ¯5ó¦4Þ—wÁïß,¿ö×­ç®§ôÏ­ßÓ/ð½Òc¯§ºæÕ[]öyæ`9WIëOÿ(¢ë© ÑoF¿‡ß’ûiïká>‘ö}.ž¬?û>•˜ÕËwÿ§_�×ë©‹bÂb‰Y~lù¾}œëí0þO›g^O ńų…Vsßçmiyóf¨=ýXù•]°or��?úSzaÝý´yxÕ3(æñü¶š3¼L�§wéf1åÿô¹º¾e=� Ø{úU\ò}ûÏè|°ïûôû–)_x=Õ)öó]ß~õ{†{±Áû>=d¸í{ß§­^óêØŸbË©åƒçUß§µÒISñ}zÈì,Ðþ+¥˜¥ìºÏÛü>UÛZ5ƼžÙp=Í]_ wô§•¦[*÷¯ß÷VK^ω̮.íî°×Ó�ÇÝ3ûSníÒš¡c ÎÒ]{hVãB3f´„a- p0½Æ?ü­žZ«^VðÏ¡Kè�ë!®¦at|�˲¡7Õfeë<¯[:m·Û‹,Šøá�ì@hf“¦â‰Ô[�0ò~Œ:ÂÀø±iâ[,v¶šYÐm 5 wòemGšÛd>/|� +‹‹7ƒî“Ýî[hÑÜ>ú"ô‡öEJÕ?N¯¼�êò‚³å5VDÚ¶#å®–lH¥Óò• i{yyÑB:\üR.mvŸuxûwéçÉ@º×u Í>ø"òn1^HuoœÄæXY�1vxõAúðâ?Ò…ú�sØ}çXIìà‹c‡/o¤›©‚R‹´Ç+¾&‰/RôG®sªÈzòIŸ}p¶*�íŸà–Z»×ñO/´�°øûZ»?³kŸ–ü—Îwº¾(ØŸKä� Á}Ïü u.mÉ´íúXÕó>ËW»ºN¶^,v×׬?ÛƒLûZõ�,Õö »90!f€myééö¼÷TµÕ¨!fÖˆølØ®¥õ?k'}q ]i0è mk 5qdáˆÒ+¿”jÚüséŒ,ŽMt¡y±ìÙ‡käÑ Ë7çðuƒ¹ñªAÍçw%/HŒ¼l#¡‹òÔ!ŸN“?È’wa]ú–¼º”Hë�z¯ëž¬1+;Ô�•±Ñ{f0 !:ó2.YD÷&9þÑ»Îõµœ’{„˜HEù:W½†Ïà¢9¾Ußñ¡ã{ã;‰G›Aœ¿¾‹CC‰¥ƒJ¤½€Ñ«å?õ0`Q˜}#oÚý™9kïù7˜î‰è”×èqJÉqÊ>‹)?ʇSË©z²–êÑí>ôçµæœZvÚÙ¨=¨v<#w°î2Q>>´{­™äõéÍZmMû£ÓÎÈôNríCÞ)•vµí-•$—ç9´—Tš³ghìÎíõI0¡q^öŽ–±ß—>]©æ¢ŒJ9/,ë³?Áì5‚å¶?ó€0¼·õÁB§†yÏ.C÷î«>Ó´6 K+ûaèCÄ¢†ò%Lñ«ŸÛ2xÇäd’ò¦1íeæa¢sÊÝê¤ÉoÔ½¤N[‹)w�…ûqàL.Òk7ôþyÒÇ¢¯6L0hÆLíÈwB�éÄ?0�V{’7uÀâÒ‚v`gf§l=ƒ±Œö<ûµ½×z 8žïRÊè¦8á…LInrJÚ{¾6.‘öU>Þ<ý- }_�11¹² ÍÁ›y&÷üúÍîRdßéÁº Sd墳çÔÓn³”ÐX×2¼�íútéìRï�O—ì¹ ­Sþ.�9u‘æO^rùüŽE°Ï^°C§ÍÄbQfpïügf°YdvÕ›g9̉c}`ÁAL<Š…øuñ(ö¦Î�bv�6ÅŽ-¢:¸Ž¶ÝJÈnÅâxÇûqBÁK=V¾ÿJE l¼¥r´³07©,ßÿ.E”5Ÿÿ2g[Íõ Î}t•:^½I¤™òÃÂòŒÔÙšfÙW'[>…·k¸®B:‚X +ÑC<ÿŽh�D:*Mœ¾e¼ŽhÞÅ~¸Ø»"Ü�ÕüÜÇÔõ“‹U¬XÌ+6Ô5­$÷¥‘y6 ¶t6|:@ޝfHܸ¾'íÀŒ’Ô°)}§Šs.ˆã#öïÒbX¼Y¼ŒÒ!y�+€ƒ8 +À=>G¼#\‰Oto’;<OûââZ?_þÏ.ÞE_":ƒÕ]{îEÏgLÆäzÄÜÿÅÎ�Xî™»ˆD,÷eÂÉ\ßWÄÙ%ù»èñC·ˆ{iŽì’O†¸vaÖ\¡•’µÖ,œý‰Tü:ýwß ‰#)ë7´•Y†¦iþCÜÕp¥7vèñÓ,³N[šà ]>øe¦��“'¬êyŸŸC\~p‘ÅÊ…&,×çRÏ{û–H!ulªÀ‘ipºÒ»cmÿ˜Ý™>ˆ’L w¥�,WÚO^"Ðný"ÜË yK?CÈî܈+áb5y9r©†–õZ"Q+MÊ1øÜâäÁ‘ÛòM5 ”ÓäùæúÀÎMš�¯» u¼¹ÓôSù²@ÓÐrr4_«Vì»7pTð[ÖñM+wèM!JÆÛˆø¼G}å^‚œÎÚo€Í+ߊ &E/®NF¡‰°HáâTçîtcÞ|�^TŽ'P¬0ÒØÝ1% ô‚¢y°pfX©° @¼Ûòùs®úz‘V*°œ`-ãô7+d‹«¯äè«¢ó^²u5¾¹ñŒ+Sˆ¹ÆçKÊ?Ê*æa|ˆé³Ì¨Ñ†ßÙ �6üÎ%BlwT�„Ùý ™—poîþf�æÊÀ°¹i´K£Mï)a^:ªF ”}˜·9h42ûÎÔØ´p‚5Z":œÙ×^ œ€õ µrÆ\Ç)zJŽsÂ\4YG¶- +Ù–½½}£—± "ž‰Ü8þæ\€�zÏ.‚GRB虡7îí²V@ÎÏ‚5cd% ,k†÷èÉ.µ75`Jì¤ôñì2tï%ÛÎ9ºtßÇòtµyñ•îûHÒª¶uŠEñðàf²à%å~»Ô|ü çm1G„gzI§"r„·p9ÍîR«ò†©Rðïr¬ �)ß·Çþ{G£ì\söË#¾âEv Ìo·- _½‰²vƒ iviãèxL\)ˆ‘òÉ~kι|‹âék |cä‡ÀÍ·ŽˆÔ%Ƶ&sã«&¸–=ÛæOzž‘…)û¤^nø™Ê÷.ÞRk·¯µT¾Ä¾bå\-j �9�žt䔀9ÔÐWÐ%Òó©¡›@ꨠӴåì5tÁtX-8�:MÖü*èôÈbæºà +:½Zpæ:O¤f�Wµà45tÁtÆÙ³ÖÐWÐYµo³ÕÐWС›G �[E9÷C{¯WƯ¡›4eöíÈ$CâW t¾R‹ í1›b ÞìâèT@—‚öO%t×0RÅT}¸éÉ?Åä^I¬ºýßP:ùy¿OUËÖ{¦¤“+Å4¹½]£R"¼ ocÕÁ°û̶š™àR0²Æ‡ex”Ûùð“×>,wü‘6ò±Æg[™,vsf®üˆÞ¥¢ked¢ë] +Ë\uÊ·hÎ^2Gx,œakî}Õ±³~$_EÝ ¼Ä7iìÎôFH×âoñ¨}È/Î\ìæ±rºb·8[A|k׳¤ªÌú´b€Ïƒ0þ[AlaH"BlTó­ÐŠÓ œ»ÞéÉ5›&óÆçÑtr£?ìõžÎ&ë¹�ÒÈ(Æ*2m,œ¸«ƒgdöýb{ VÀZv„Ä™‘64,òö·4p¥Iàí›9•Ãh'éù¹]au`®*0_§kŠ:¾q˜EŠQÇ× ®Yt$­üKÓöÀG8ŽÂÑ¥¯E¿.íÚj¬"4…ì��±‹ ½çÌ`z¸ƒ‘çOµ2˜¾¾e `a1F�œÓ XX‰LP¿œ«¢,,Ј>H+½:Š—‰Æ¤XØQ!sUÏ”ïòέNû¾Õ3Q}Y£6³¾…ÝÓÆWË™'Q„€ø^éÃ;óJãŸw/Ù¶íߟ[°÷¹ïLìz�uc{¾ ÂÔ׆ùÜ>Å>Ó1 +åÜ5#á3ôFE�xüdKÜ¢&üèéÂùÅ•þä+�õZ“ñðùa@¡rîÈlå_'g +_ºj¬ª£8a¦¥�‹îAœR~\çÐ:æ™Ã^5mѯ=�å�àXæ$ñ\ïå�E£SÄôŽËў؟Œ•cÅù°€šµÕÑ:åÑ%&B—l;‡ƒ*Ðbed+ì¸9Ñ)´î5¨SÎŒLa2#ós蛑ñá1ŸŒÌá”§†¡�–æ“‘a—Ö ËQr22‡óØA 2s(Ü;ÿ™ù<%˜óðŒL"JÚÌ\­–¹y& 8g¢æ=h³ é9E.â–Ã"»êPw®G”ÓY> +«C r–í'Q°;7¹Å™apä•ÒqîT‰µ€‘‰T:j¦t,2 m=3óЈ»k“ý)8ËÇü³KÖ€áuu3Ÿ68Â]71¶ÍúMS*x·^¤ÝƒH˜YJGíQÒQ`4´¸Î½QïܶŽjr2þ¾ø0e=\üóú¦©‡ó]Kšk=b™µ5¼.b�ÅŒõpf�…£"nêêŸz¸˜©SÖÃyW λ.\[ΣÎôú¦/ÕˆPù’™êá<æå�²:ïz8ç íFíÐÌË:zÛì•õhÞ¢.Y«Õ~)K6ëžHKóßö#í‰ «øb½¨=¹bäT&7HLU�Nà¬Íê6W\ÛêÄÃáÌ¥’ ÷2øÆÍ±Î"E ‹ëübqw<£çµêBÍ ™ˆˆbxëA;O  +­ešr�Ö#£ˆÀæµ5ùa@„p6o©%Z ñÆ+s9 X«¬†bE€â/>‘Ïî¨Xûâ÷ÆæÁV‚�޵óÛu$°÷Ùƒ1Ž˜É®Mæ°°ôÌP{Ô‹EÛK…ù¿È Òc±�ªHm,¼y–‘NQ‘ÚXhz& âU¤Þͧ"õùw©e©X/6�ŠT„3{E*BqW¤ú^¿u7_;6, ¶ Ýfäü‡Þçµ¢ï¶�¥ÎËŠÍ¿Îw^æZ +g�%pŸ¶Λbó.…‹WÎX +—ˆÜ©YJá&vDLY +ìÚj«‚Wâ�_qm�p¯ŒÄ¯«ó ‹\+6‰t„5é¤.¿=�ŽSšØLéI;ÅG û¯%…/.�¶(ç«-êë•>æ¡9 Z‰n´Ó´&ÎúŽ»ÕžúÒîŒ[óÞC¢Ï¹ sûìk¯{Ûx#ˆ×å¥Ý×úõöym·8Z©Ô¯wćêcýáºúXSwKûÂõa¥\hU*åâ^Bp50ŒQºëÎÁê9'g5V@ÝÙfêÉÿæ6ébýÜ™Qt»m´ÎNìégRþk5½™êû»ÝTØ êí¢]@\Ån×eÿ +;¼T»á‡ô=°Ân//Û�ºï3[Ï M¤îb7¼jÚ¼ÕÐ^¦ÝÇ— *v£ ¾Hs›?~vÂââ¯0~ö­°{x +ª;û ª°ë__{!5îã;V¾Ú~vJP-áŽ?ÒÚéÓž-sx©Çn¼ù!½˜`%W=ù¤óùºÇì{·Üˆ‘{>n‡XôzÇs­¥n:�WÔÜú¸ë6§Ag©íÚvÛF<ö?×›Ø&¾ÜÞ³‘ˆ\Géw[Ö$è«ßàNEî’ó8÷Ð=W±o’óò~5[9Ï›ä¼ ¢¶ŽrèzT:ùn‘Œ·¦áƇƒxïÛ”—Èy�"¬éða¦åƒÐËFЇ™¡g§Bîê’ÍîWãn¦ è’+s<ƒ¼ì)!×Y›]íó©¦óê¡{5aöj:¯Zº‰;Sf®¦óJxwqίšÎ«–.ÒÉ“±ªéü×+çYMç§-ç[M7SÖ:r5�WðáÁÉ3VÓ9œ½–Î)ûó¨¦óª¥óÒ0³UÓyÅ͉¹WÓyÕÒ™k¯s«¦ÓCG-�±Ûv~Õt^µtVf^Õt^³K²Ös­¦ó^�w5�W—¶þ̧šÎkþaLŠE¨¦‹N±Yªé¼jé´Õ·yVÓyÕÒyß”7K5�€Éš‘Y«éld1WKüjF¦¯¦óò�îÉf®¦óª¥ ¹WtŠj:¯ +8£{Êj:ûp�Zºhq¥/9"–ßø¯¼O[Mç5 ÷™ö±ªéœ] +*R� ÇŠëŸƒ¨G7…DIa×TF«Åн ÄÝNþ°ûê¼½‹yßWùÞ„Ðûê¢Ö¬�r+Î}°ÓÒ©: +v,&OÔ ¸ÊÍY ·K†Ï媺¨å�“WÐúW +‡Ð)Ôp�rÐ)ÿ­ñº„òœÿôR™Îˆh‡>ºRåì’bèºánúúÊ87ÜéXüÅp.7ÜikþwÜÅCÿîbV>NYOäqSÞìb8qÃÝ 7åň¥oÊóØ7Üi·ÿøŸÌ]=ásÃ]Ø®›ˆ…µwÁÛ›¢ê±çßYÜœ‰Ú·¹Ö>ÿºo˜òöµÈ·¤W>žÌ¡. fßsEà„ÄP‰¨pf +Ÿ m9±¹fêúvíº¼ =ŠñëÛ×3kb¸žqW&{ìë‹$†÷±Š˜<³pΊ°W_g2r“yƒázÆÿz°XËMÊ�Í™ XÔ£ÍX©ôÏ[:)Ö‹pt\¤¸ò>jSPÓ›êkg –x5®÷ñ‹˜Hmµ¿kèq\")•ŠéúÝÇW)̾ÏÎ %Þû6¿×ßÓ‹^ãúÿh*ÿs®æsÝ£qSÞœj\+…¢ïN"=̯Æub†/GLtiò "ìÔ®{Ô3@8 Ç"ŽÅ‹†ë‡oû[×ÕoºR.ÞU•ëêNîêz«ÿžàÓÞ¹VÛwÿ\o3+Û UÍð�Ä®�bÆgGÞéÎ¥©£n¸xûpnOU9ïa[¯<=¸êáluIþexêø}�öEJÕ©U¿Ê?aqI¼Ì¾Ø£WgÁÖ³ÁáB}Àú#Ý[|¼q!%šß¸‡í Yøô»‡-PšvÎû×à WÄeնךuU9f3;O]ŸÒ´là�s wåÙ¡jøhóÜ©°˜æN«ï~õpoH÷–‡¼¸/º»X|ôA*í;J+ÝH/]Hµ}&ÿÝú#­ÕnêÎY]§kæ'½s¼ºUtµÓ(6Ù’­P Rï«ë¥í€bëýQÍ2“0êνkÁ\®ñ0�•€ðÉv2XÄ�“@T>ë\ ªFÝ6á³­àÒ¦‰ ‰Gõ�æóWcn­òïRÅs_›íä–¨¥MÃø{ɽ}˜‰„n´­UžURh×#î„ ¡ÓUÈ´èUi¶VE­J Ù£…Ÿ Pö%¯�=½aUwwi‘E@§&öiÅï©â\îÇÚ§Ô%ï,ñòÒØ¥¥÷Æã¦ —ºª=o¯:ÕUmæ³½ìƒ †!ue¾Ú9öÝOù�­0^á¯�†™CzùµfùùSçÇb矫ÍcÉúµF2Ë�gEªØD8„6�0ÓF-^œ\�GÙ4â^`Õï°›Ë1Ðõ9ÆÈ�züd°_ž îü¬X‰€F}2Ï÷ä!gN…û�8uá[RÃo/�\HvtÊYøŽRÀ0¿Ísv½vª´÷BëÛ£V2É)«Z0Ê9þÕmA'£FðÆ�ò߬¡ОŠ~/Í©”Ó¹¦HVy¦. ¿ôJe»e&Xð½Æ¡ý²*RØäÍÆÓrb½r&`aµ×}IÿÒ¥|>÷#ÏùR¾8Y¸é/åsŸ¥öï\Êç°bÿÚ¥|žžRT: ¾3éMøÙPñîõ‹w6Ô´÷úÙUÔä­~SŸ åº×/xóbHÕsä{ý‡–™}ŸÒá|ΆŠt¯_èÙPs¹×/øV¿õ•3ÔBxÔ$Nu¯Ÿ—ÃnÝêçºÅl›†½nõ›¦’+þnEÿJ®x÷úßê7óý•ú½~³å-£Þë\uG°Ìá^¿àýúÑv¨†ßëµ¾r¶{ýò0Q1ãÉÉSÜëgîyº ,ν~Á3éW•6§rwýV¿yþH÷ú[»¨» Ãîõ‹~ßÌ5ï¾·úMu_l“ç}ß,hA±twàŠUŒ{ýµå<îõ .OÑ2ð³ß뼩À~“5ý~¤tÜê8/¶•š°{ý‚oõ󮊯_°;V•6ŸòNÝVέîÁûV¿Ø²ïs¯_°àyß÷úy@Y ›ýø÷úC ¹�/ò½~Á·ú¬ñÅ«{P‚nõ#zl÷úßê—HÇCÿ{ýbV¥Í­ÊÚ~«_T=v¯ßlÞxÔ{ý¢ÜÇ7û½~Á·úÅ»�oZñqßÇ7í½~N(îcþ¼+Sâßëç•L‹u¢N¤{ý‚jr®õîõ ¾Õ/$z�^ x«Ÿíæâ™îõ‹ujÓÔ÷ú¹Ê]ëYÓßÇ'›xßìÅðú­~³î¹2îõóIgëjô�*3ßëåìôÙïõ Îk9ïäšþ^?¯ò1+Öò°bSÝë¶k;‡g¿×/8lwKå´÷úyQ,âNÈ÷úEŒ+g¼×/ÒîÁ™ïõ›p ·ú™Xf¼×ÏœXÏ[ýl§ÍÏt¯_pAl",Ø�x¯_ðŠ��b3Ýëçì—;99µãº×/xq!ät È÷úßê§�Û3û½~F—¼ bµ5ñøg¥=ŒÃ£¯qÐjxo¢bº½÷5q¢"ùÍ ÓØx?yO¢GᢋŸ4šX9¬í­�Mçê.›Ž*ã´bï…¾Eªx¦æ$Ÿ:bÑ㡪2ÃTîét‰*Þ‹Z¬§J-�l¨L/Ul= 8Vý:¬ź/òÅÍj&ÿ“])ÿ–©ýÏÓÒâï¸,¤žm>½ï.IãÚòÉÙï%ÿûýð$ò®%�Ôï G5ÅïqïåËï›�öÕ‰p÷u­œò¿·åc鮔媮/�éïõîæ}_ÙÉô~ßÄß´ºÛNSw§;+KlfOH<dÇ_‹O\ÿYY'SK*;·o®¯nS…ÜënŠùü½Ím²+»T½|T¦ê­CjOX¾TÕw9£¥;�—áâ«Ðòͧs³ð:·UÌߨcyÁ({ûST‡Ï}¼lN^ô^õuT—n<¿É¥ÖÅÕäÕÀœ¼OrüN§WK»Ç‡^Ä"ä€áŽ–U•]JŽô+ÓXQÎo¯·—zjæe™á>Ç‹Ývª�µ¤‡Fqhj¼6àNq¿ÚI�Ô$¦Jõëë4µ¤´á·ó¾Óa¸Ä†v^±2«z>Y³•¶û-A­yQb[HWÆÕǺrO®Ï¬¼ì]Þ §•öÂnq´y¸[¶7êòâ÷yín—}²õ¶÷º·÷ωti_H5Îí¯V»@3Cç¾E,f|xÝÝ8N©dT¥Ÿþñ°ttw÷–«ÝÞïã'îy·€E»kZP¿Í?¨$r¢Š£ îEx1r‘/¬Ÿè ÉMÄ|WIÝ/(œƒ|ÝZ#_ÁŠ=©ðµR0^«ë5æD°ûT®º–×3ûôÚÊ×["mtô(k$�惜ýÁq®e>ÈÛ¼ŠŠù h0¨|ڰжG{å_¬/8]µÿv“i�O×ì>¹¶ù @î7¤÷—v)4 Kô~¾Î»JƒKÐü¥Š{7 ’HÔÉ•N£HSEà,z\Ó x~�7x¼ª«£óãiB6ÂÃ×KŠy6iøÓƯ÷ŒvŠæ*»s üЏ™ìR!«OÞÙÀR¡7t¤g‚…-K¬´¡¼f?*_Bý¬Ü•%[´±}¾üC<%=£è2ꮸÀ^ãƒ�¸Éhì e�n¶Ö+¥›å�÷Ê—x4(]—zwh d¦ü´úZË>1ÙÖ}ǘ—kÖbqð“eB´ûÍã5SÀÄ…øíRL„dµO�…Û<ùä¿ZÕ>•Ù}47ÌËxó€|b—äŸøä±IžÈbù¾çua�†”VÈ#€]ÊhŸK•-}J¾ŒÙ›& ¸Ù1|r†¨<òæXšìÎM÷ã½KÈcÂc¾Zll.¯öVnê›5îÏDÑîÞý…Çj–ËÌñ¦�+GOEì!ò]‰Œ¹@²p‡9íW[¿GŸ,ù Ü®\�ôÇê�ðø³ß­~¤‡×»›;÷\éèžkÀ¿ð a.2„SÙåNz¹Öúþ•Í(I·ö{òˆi7Ð�_)È@�–SÙÍS.•/®Ü¢©®¦–ªÒ¦n´·¿wi|t˜Zûœá£�T¾Ä¶Sk'÷û©ÕßEÕfÔ··úè:‘b‹= ªë±3eU8“7ˆÀ`yrÚ�M­Ö#(uýl¨XV<¾ ·¯YÌÑ ¸¸ Æòo8-~<—Ô±† >Là€½->æD:æ${ÊÕ¬<6«·¦ —™ƒÚžÐu®{’ת— n§©Ücf7•ërõÔÚ[û¿®¤Ö¾þ¼¤r­<½XØHå¥üYjep³D¢<ˆø ðƒÏLý +ƒ½m[Ä—UÕµÔZê}þ[[Ä@Vú•ó­fÏôC¿jÏõ_3<ÜÀ‚�ÝJ§¾¬îÞ®Üÿ‚ëï«õ·µýÅÒÙçæ1†[ª~\ /I.s˜zY©ês°õ¸Hü¶¤¦ªÎ1‡`ÖÖø4ܵÆ{í{·÷[|‡\>Du'Š_éþZ0Ò„ï€/ª˃EÔèM@ßz‹�´§:]s?Ì Žc̉ô,=ª)K¤ƒÇòJ¬Iö¥6X±|ÆÓSŠoD­“ôæâ.ùxÎÝÿг ˜éøv~‘83Z¶‡f$‡5=³“()åÝè#ŒYó-g²*©Õ×îÀ³ÌɹµKÄÒø-º6GºPHeOe4»ø§ŒfâTûºº²¸‰ä Ï1‘#|P@ss…_ë˜j\û²vûJýöŦ ŸFᆅ«.ukìP�AáFÀlœ êo•ÝÛ£­�ÀëTí]8ûŠlXÿ?·/^¶-.æ°á&ÒÖ€QÜÿ+ɘûjýv©:™‰9p�1­·ÕÝ�篷jáò]­|lõšóq¡ÈZRLûŸÅ'Ïîø7¸Mߣ8‹`Gà6˜ý8â5åpÑSšB›ÌÂcq´I,አÇ"O²¿pMÏcq„+‘/\–#;Ò\æÝ¶]CÝù×_ÎOäÒ¾ ìŸÍrùýtñ”|•kÒ˜I¤÷ø1}U»+_ïG;G¥}þ¦P}¬ß^ÁWª¾¾Ü¯®WÛ5KêÏ7Ï?×´Œ¾¯oŽyŠ)ÏÁ­ +ÊóO©Î#OïEë¹ñi<ÊAŒ¶{pžéW/ô3ç`#q¼W~Ìãž1ˆ‹¶Ö2f=?6×PâßÌÁEoÎüØ·¼:U~lEMåå{- �ÐDtE*¿Ì!V)Õß¾»«õR·ñÇKÀqÍÂ!âäÀÉÕÕñû±hîî(LÅç+™J'õ” ËÁZ¤¶¶,æ³je}j #ì\®>—®oþ¼Fânò©þ–‚OkÁ ÁkIú€§îêòÁÆôVlºáâJ"—mN¿¢i¸ÄVÎa~ƒ‡‹«Õó˜ßàá&Òó™ßàá&Òó™ßàÙ��뛞�ÍÙ�jÅ*öp5‹<ûüW_ ›_²Õ©ñËDÝ�ìèk®ç¨y׊¼ÌÓíµenýÅœýÜ¢§' +µ�ý�õq×¾y�DOÿXž ¥,ðE ù ¯~¹0‚5gï(‰,6w®lž× +N_fž_wœo·ñh{÷m–vù‘9´�^Û»¾yf¸˜0^´k˜Ôòþò¾}g"w¥]+ƒÌ—Ím¯�2xGnßÛÏá§‚ù[Ñü�‚OW¿¸ÍZ%;!)*Sx´Õ‰/›£þZMo¦Þ�}ê[LNߢÎešK—Ï0aÜn˜wÚÏÌ�ÁºäÖ9EºžÛÜø¹´89û mÖ'�6º7§v¶ vɼ”³G9ã‚ ý—ŸÃ|°Èð¼?ysÖŒh%бâÙ·^:ÀŒi‹§s­³ÜQ¹`ôÆv‘Òª�O*Û´Ýãd’ ‘ÎVÛ¯ +yÈå^íD`>/L<ÚI½±“`´ýKH€œìK„Ææ©Eö©KK¶Ó€_†Í‚©í"¥ h¶ÒE„‚Åý÷©~±¦A-?¼ýš;î\ ¢ÎÆySõÖ]ö'A(ÃÐÙX]²õa§òÛwø²±”F±ØÃøÇâJˈ~*œ�&O]0<üص%µòÐrøLÏ&ï<ØzKÕ_öÕ�oäÞÉc®N‘*¢YÄõAQýx,*›>|…3ˆÞ?{øžQë<ô,yuòXäa¨ñ´Ž�=Œf“øÇÅÅp‹Ì Ÿ-©•Û¯+;ˆfs +­ã´ÈMå7Œ!}øòÔ:h‘£R¢ù=œ’#L‹Üì�fS\Í_­b‘1ä‚t?Ö3²-)—yZå0 w¯í"X;¹?Ó¼:RÕcÖâ�”žë³ÝÁh¬òä´’B[ _ýíÍ(‚9ïuBWzíós;G6fkåß ZI VŸ‘EQ;…f ‘2ú§? +:ØûY½iåcäýœþu=“×z«}=æŠÚk7ë#-`Á#«ˆ’aîB«(³Ö#û¶·r¶¶’²íJÞz`/…Û>(Ú«�6>K–3Ú|ôªá{[«ÖovÌ{•5Û潃V³®2åûgRê–¯ýϘÔ%]ÒXš£÷w.Y Ç…½B´ù™CçübM«Fj-‰ëúü­�ôµÂ§V~ c•‹"‰¦èÖÎNØ­¿qq£ÕŠ^àÕ¤›‹¤bïˆMëõœyçàÚÆ1LvgwÃ̼^–»…ÏÕÒyëã¸zt�º²öáki<�”H;� *3Ùýúf|8P.Ž·L(eÐ0£ó%eïåQú,]�—:µÇö9…# ­rLæeüºkT¤¾²_s¶AVwD³¸÷Nã@¦zQÁ3 îŠÆùcð`7_²ø‰6ŠôîHy`?±æ'NQÛøàë£ñ­UÇ9},ï>Ræ'°Xýyg^ÍÒÒGÖþ ú½¤ Ã÷Þ¬ØìK±Ý«tmMξînP·Kö…SÑ�; ŒÂ>ã�~X›~¾Ú6ÿR°�²ËÙ3$ê üy¸Ëà'ÚüÄØÛ�|røçÜw¡÷ç¢þ~ûP©æ¤l½^;¹•t%4úá)¥¹.�òNvisóëµ£\+Z5äÖƒ¦PH¼¯Õ¸®t¼è�¿Èɤ¶œËXµåf©ãЦFA'åt�„Ù›Nzè“]²ò¾›zѪ*?*…5rÁ-©È-vîG�M;kë9r2è‹Ú¡×±$ìÎí鑦-Í?øà°ˆ*΋K…‘BmÐ^F—�t±_»¡q,GÀEâí~åý»Ôvh¯cÊ(et—œ ÄŠ}žåHå¹1BÌ>—ôÙ�ET9aÌ¡©þh5—ûù:j˜S;lKY™[«ÿïvB¢%1)Ѳ�,^Ž»Šz¦v>;½äZb#Q,ÐôM¯Ý¯«Šr­ügTí·Æ?Jo”\OKW•ƒ‰¯*­~[I®i›D-^Èë]Õ�öƒ=BMET?ä½ïýÅË­FõƒzØv/feÙý-\̺Զno¢!]Jåö~Éþ»«TZ¡É§Š¶°…µ½ZZ¹‡Ì‘Çq,þè×Éh^Îàúwùí#–4šð'mÑ,³?\ïš� 3â<•MÁÁ eèC�í ÖgÒ:Ä«µxlªaìç둵Ž�í ÇôL¤Üß¹dB-²º]¤Mûܨp³iÑ|MÇÓ:‰´»ÍÏ\.„!}Ðn­cX䨔h-‰ùøa·È˜Ù)̤¸ZBÅSë„[d²?Râ$Z±/A/åS-®º“{»‡hyïbdyQ�â!&5s‡àõAXø9Ò²T$)mß`{—ÑG´ÂÌÚëú¦ž)==ʽÿÎ3oûí5² %­ð˜D’& éŒ,n´ä¾qŠáâ +¹òúÃeµºö¼‹!®ç´|ãÊÖå/é­öõe¨h‰H+`An%3ÎŒ"Õ{7Ùóu`ïÌLà‘=&ÈÌì>·>¬hÙ�Åu"Éæ�Â5Óœ§öãlA š™«S{’&mNÍdÓ)b!™Bvt±l§!š°/rZ�ä�‹¼éó/3dðÑ‹‚žo*å‚ÂëÇUºµF¾’�b$ùøD‡ÊÖsÅ“«o”§k-¡Éd…u“0×…øé«DÚ#Áa¦¯®‹Ó$Ä&áŒDÊ‘..7s7ª°}Ã�–Ä—vFOO>^¥tþ}x²Nh}·Ø‹ÉŽÛßfªqÍžOfªû[hÅï +zòñ@KŽ0ÕÖ¯êÞ0ú§ñÓ«VaYË6ÞôOÌ'&Lîx=ßø¸‹ðáO“Íϼu�µ4ó6¾Ôa¿gïMn{dì©Æ�öóg;JÖËû]ªâÊ'ÒáùÝeó�;¿Ë¦Çf饨†ºÌÜpúé¯O¼¾dÈ.WæÒê «·¼ý)¹ó×g•ë—zµ»Ð*]^?¯Ôšù]rð&¹1]Ïà�‚–JÕ”Yý�7·ü�ŸþNÒTò$ùôB%Ûã2ÁXJ¦eže%ša!ÉI $†XP[²”ü�6Í1˳2ü(ÉI¶@Q´ÈÒËòœÈ2I®Àˆ´DÓ‚@Q2ÏÑЂ•A¦XJ”á]Z‚DS²ÄÈ‚´�Q‚ï¢(qÏ%[ ¡@ɂ̈Íó2#IГ¦x™eFNvb�•%Zä( +qÓ\’/0¼@3¾*Ã3hÃd‘–^(MqI,Ê‚Èó ÃSŒÄA¡@ó,'Â?’,b„‚À²”$#dIæáF h�¦%ŠrðI±À0#K ”y†´�(ŠXAptІÕXŽâ) †$dŠa9‰—`4C'¥MC +ÆÍp8[2ñ:epÀL¢èƒrÃÎBc蹄Ú6:�€Þƒ x(lã…nPÄ/‘iÒF†i£ÀVAAk€5åÑô±07¤ �¦l³«Ë€aÄÙcÔ_[, Ãž+tµ …|œCV—ÐM§Q²4QÓ@h šˆšÜ!âs2¨§€JàVò8jІàcáTƒNÕ|N°ÿHGp×A•‡1‰HB о€^¸,ÒND¥ nXg0o4þI#0ôè3 šlDñÀˆU%ôÀÀ(Ó"Z€$5K2/däi›P8Ó ¤Á!â8¢mD ™âÁZÂ\rDìAÙ‹`mÁ-`¡!i–<à.tNÔ´9Ch*ÁÐ(DÇàƒn{ƒÓ§��žÇ�I º¤¸?À¯À`ßµ6(½`%Xh(¡²ß¤�G]|ŠîÌ&ÐR>±ÿ0(…†ƒAƒ}ÀM„Ùo�¸8•@4&ŽE Ô1tÐxü3p5@8p{€”_ë2¸œ`�`ÀVðºH`û0ˆàÚPÄ‘ +<8Šè½¢Æ�‰ X�Ê@q %Í’F  �A?‚´‹,6âIœ®xÈzl,x]8%à¾ðÄÍd€ûi +ÕtZ€Ã #KÂäÈ@ ì x© jPÙ#:P 4J€ôB=gà8˜�Mè� R,@܈КÁF K`ZÐÕÝ)’FxP"rÎ3ñ�Ð'Tü¢@üneE Â]ô 9½� üC f‰µ�©‡¤A@SˆM€;a,DÑðD­€;Ž!Cþj¨€Ia¶À‡€ A­�™xƒ:Ÿ Äi¬ZˆF8à߃� ¾'A/ñzá#h| ¨ +ↃŽ@z€¯SAšYDt_�´Š3¨JôVÑM‡ÿ€„}**И Œ‰>…‡obpŸ0v€þHè�° ë­7bÑ‚€ÆÆé@éEù ü&Yk$ ,‚B�NQdî)´70ƒ€�Â��ëƒî8¦dWô-%”fŠ˜ Š€�¤=‹2È¡€sÍ¢.ãŠÑèK4SNòØFB3#a…J{¡¶L:^(>¨¦ RF†•4KÁâà�;€9a"9"Ì n$Pñœ£k¬5)a^¦�H<#° *�_*›€�GS¨ab‰[Ä +çaÊÚ‘&p°€†‘¢œ…J˜? )äÁ è%b#°Â ¤A¥`VÔFfû �ÌÈh4Ð4Ê9P +Ü)ði1¢Ât ¸ R­$˜rpö–'“Â�fäPjÑ�PªÁ톆ÁHL[APhŸ�ÐAÌÂvPÊ„J&�@n€qXšäž€ÉDð€ÕÑ%F= ƒg0¸fAJEðÅ1.þûþY(00­ÀÃà±0Ï ‹ £�éš ?�¶�ƒpNÔJø‘A5%³h)°‘€�!ãQì1Í�þH0Ç"̦€ÝAÀ �Œé2^$m€} Ö½  z‡)·Ìø¦0#œ Ið(H�i*‘ ”¨M Ôx™x¼ÀAàæP`ü}RKà¢@�"Âdµ¢Ì(N~¤‰Ÿô*E4nćbƒ™„I%~2Ì'ð*ñ)¡ ƒ²€a«ˆN6(ZP‹æ†ÃT �3¨Vp*@ˆ9ÒDBk ¢Ó©±'4¡0y¾fý<…n¨F +=zÓ>àbpEƒ;Þ” æ|wpCP|´äL( NFçS‚ìñDÙ‚Uc‘ºÀ= „DE:�:àb`6"Þ`AG� ‚ÚC§‡àúÅ~¡&r]u4�ƒ:,>˜ôfI8¡Ë¨³Q×ã”S˜æ4ãƒY!$“„ž8àè,T¨gµüˆ;̦NPÏb_ÀÕÏüfšäoQù�€O ÂÜ¢RxàI€V�­‰*y€yQØ€±ÑCg�T`!Ð�ÕÚexL%ËŒ¨%!Á_¢hô�XÌ@�6 @™ø€ÑÚ€¯‡¼„.ÉO‘Q?€uñè,'K Ò˜"? Ÿ –D^ä´t(zS OE´*šüИ°)ÄXŒ Þ†è•ŽÈ r ZÓNѹ€H+� ¸Î$dž,° hIh4BdšÀ£ À•—ÑÙÓÚ s˜Ñîdˆµµª‚dÐ�Ác�Ñax�J‘$ÆÀ™F»Ž2p(( 5yl +ä–ºe í¦ˆÆdK@_‚s‰s’ ”`ÖÀmàÁI»%ÈD ^… ç„'bŠ4+ }kÌiÕÉ£¥%i4O›`hâ¹�Àú”+Îh,š¨X0� Áx˜e2h†9ŠG%ŒÉ9 %Ð�S2&DÕ2¨-:´A¿“î0¬D†$'–õý“À‡…9ày ”f—e�HtŽ0ŸŽ$ƒ!8"­6lôÞ%� dHQ&pôA=€ðâ�0S)»(è´P ;$}GžÀ àz o¾´àDP‡`„ET ¼Á $½Ãápýýa0¦2 y1qмɡ*`0É®¨>˜6%A I�åÐ;G™"Ë0heTϬÖsØõÁ¼�jI¢ŸŽ 83Иð<¨)€-€¤“Ò„Ȩ/P]€&¡~7b6ÌMÀc64  -…AÇ +¢j +Cóa $Ð]d’°% P—ÆÂ0rÅXFN£Ãjm$ Ž0-sÉ�1IÈóàHÒkp€ž€ÆÄi‰(bëÁ™·ˆ#iy˜ÐûÐ}˜ Ìm`zØý6€Nt"…vº†v’#Y{Œ/@× +$½Žþ¨lð 1C:=;Ð ø +Ƚ¶Ôq=Ø5`fLòbTâ¡SäØ&ØfüOä?„æ,úô@<ÍùÂä4ð†â,™} $M �A�>Ðè=‹˜Ë¶#1ñ nO€{94KH9Ž,`a +C0Œ´6øÍ*°«ˆmÀ>á;²+Ƹþ# –”�t,†ïè¸HšÓ „&W/T4e"š6t[x âƒC +3膣H£?‡Î=úµ˜íÄø�¦ÄM? —yBk;lÕÈ3˜^¢ØyJ[pAǃˆ6¦pi’¶ +Áƒi¥YÔ34étD 6ŒÄðÛÐòÈú0A˜Æq• ú‹4&Z½Q“ æ:d9–0z—8bÐFõp•€ä +A�@<Ìct +oi’öZ¼�HÒ’BèêÑhGAÒ�& 2ànàŠ€Œ©Nô ÀƒC9%«Nfq‰'ˆëhå0³!Zb¼`€h\�EÕ(�¤$&‡!.£ÈZ‡^øBK ¸¢Ab<``h�'+!“ÓŠ0�8ÕQ¦™x…7Þ+è°täŸl²x5R;½Ïd¦\.µZãŸËþ¨�Mµ%ô<`(ðÉâ¥Òèâ +»œ<øôÕQ²Ü÷ÚÃä±ò1ÒZ¢=òmvÝè­D&Üeçókd`ËéÛ°Ü�ú?¶e~9™É&ïïÇemëA­×&{òùD:}ÞøT®ÕF§«¨‰Ïaã/%ÙèõpœÊž$?Ue8ê«JrøÕÿ�WŒæétí¬žøuH�ù endstream endobj 14 0 obj <> endobj xref +0 15 +0000000000 65535 f +0000000016 00000 n +0000000076 00000 n +0000021221 00000 n +0000000000 00000 f +0000021272 00000 n +0000021613 00000 n +0000023200 00000 n +0000023088 00000 n +0000022962 00000 n +0000023273 00000 n +0000023453 00000 n +0000024600 00000 n +0000041954 00000 n +0000065576 00000 n +trailer <]>> startxref 65764 %%EOF \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/Contents.json new file mode 100644 index 0000000..d05fdda --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-80s-hits.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-80s-hits@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-80s-hits@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits.png new file mode 100644 index 0000000..c219a2b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@2x.png new file mode 100644 index 0000000..3fb5168 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@3x.png new file mode 100644 index 0000000..6a2d1de Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre1.imageset/genre-image-80s-hits@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/Contents.json new file mode 100644 index 0000000..ceb809b --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-country-hits.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-country-hits@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-country-hits@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits.png new file mode 100644 index 0000000..5c39a7b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@2x.png new file mode 100644 index 0000000..ec9fe7e Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@3x.png new file mode 100644 index 0000000..6327f11 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre10.imageset/genre-image-country-hits@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/Contents.json new file mode 100644 index 0000000..43bc629 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-dance.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-dance@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-dance@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance.png new file mode 100644 index 0000000..0deb7fe Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@2x.png new file mode 100644 index 0000000..615b98c Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@3x.png new file mode 100644 index 0000000..848f754 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre11.imageset/genre-image-dance@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/Contents.json new file mode 100644 index 0000000..315e1b8 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-decades.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-decades@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-decades@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades.png new file mode 100644 index 0000000..22f6968 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@2x.png new file mode 100644 index 0000000..ac96c65 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@3x.png new file mode 100644 index 0000000..e74d41c Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre12.imageset/genre-image-decades@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/Contents.json new file mode 100644 index 0000000..2768912 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-electronic.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-electronic@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-electronic@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic.png new file mode 100644 index 0000000..e2b396d Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@2x.png new file mode 100644 index 0000000..2b23760 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@3x.png new file mode 100644 index 0000000..8682d6a Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre13.imageset/genre-image-electronic@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/Contents.json new file mode 100644 index 0000000..02f4d01 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-gospel.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-gospel@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-gospel@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel.png new file mode 100644 index 0000000..bb7b8a5 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@2x.png new file mode 100644 index 0000000..ba5e7c1 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@3x.png new file mode 100644 index 0000000..a77551b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre14.imageset/genre-image-gospel@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/Contents.json new file mode 100644 index 0000000..11e0053 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-hip-hop.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-hip-hop@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-hip-hop@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop.png new file mode 100644 index 0000000..ab1d5ef Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@2x.png new file mode 100644 index 0000000..896adb7 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@3x.png new file mode 100644 index 0000000..202c4ab Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre15.imageset/genre-image-hip-hop@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/Contents.json new file mode 100644 index 0000000..9916497 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-indie.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-indie@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-indie@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie.png new file mode 100644 index 0000000..7e0e67b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@2x.png new file mode 100644 index 0000000..c0a096b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@3x.png new file mode 100644 index 0000000..3f57e33 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre16.imageset/genre-image-indie@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/Contents.json new file mode 100644 index 0000000..45d433b --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-jazz.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-jazz@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-jazz@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz.png new file mode 100644 index 0000000..957b81b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@2x.png new file mode 100644 index 0000000..129e16b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@3x.png new file mode 100644 index 0000000..4ff3f91 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre17.imageset/genre-image-jazz@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/Contents.json new file mode 100644 index 0000000..3236691 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-kids-and-family.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-kids-and-family@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-kids-and-family@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family.png new file mode 100644 index 0000000..c51ba50 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@2x.png new file mode 100644 index 0000000..6341f74 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@3x.png new file mode 100644 index 0000000..ecd6843 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre18.imageset/genre-image-kids-and-family@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/Contents.json new file mode 100644 index 0000000..fe8bb65 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-latin-hits.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-latin-hits@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-latin-hits@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits.png new file mode 100644 index 0000000..d710a26 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@2x.png new file mode 100644 index 0000000..46f1991 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@3x.png new file mode 100644 index 0000000..a1f45ce Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre19.imageset/genre-image-latin-hits@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/Contents.json new file mode 100644 index 0000000..5921878 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-alternative.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-alternative@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-alternative@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative.png new file mode 100644 index 0000000..4098172 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@2x.png new file mode 100644 index 0000000..26f485d Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@3x.png new file mode 100644 index 0000000..41a2580 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre2.imageset/genre-image-alternative@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/Contents.json new file mode 100644 index 0000000..47da909 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-metal.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-metal@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-metal@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal.png new file mode 100644 index 0000000..7883ee4 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@2x.png new file mode 100644 index 0000000..94ffe3e Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@3x.png new file mode 100644 index 0000000..545cc56 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre20.imageset/genre-image-metal@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/Contents.json new file mode 100644 index 0000000..0f50fc5 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-modern-rock.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-modern-rock@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-modern-rock@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock.png new file mode 100644 index 0000000..901198b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@2x.png new file mode 100644 index 0000000..c620aaf Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@3x.png new file mode 100644 index 0000000..04cbaa3 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre21.imageset/genre-image-modern-rock@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/Contents.json new file mode 100644 index 0000000..cab40cf --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-pop-gold.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-pop-gold@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-pop-gold@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold.png new file mode 100644 index 0000000..7268e8b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@2x.png new file mode 100644 index 0000000..5a937d6 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@3x.png new file mode 100644 index 0000000..38af367 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre22.imageset/genre-image-pop-gold@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/Contents.json new file mode 100644 index 0000000..4403963 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-pop-hits.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-pop-hits@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-pop-hits@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits.png new file mode 100644 index 0000000..f38cb68 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@2x.png new file mode 100644 index 0000000..d6a8679 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@3x.png new file mode 100644 index 0000000..35b315b Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre23.imageset/genre-image-pop-hits@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/Contents.json new file mode 100644 index 0000000..77dc79b --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-randb.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-randb@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-randb@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb.png new file mode 100644 index 0000000..2ca612c Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@2x.png new file mode 100644 index 0000000..784d228 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@3x.png new file mode 100644 index 0000000..28e6ec6 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre24.imageset/genre-image-randb@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/Contents.json new file mode 100644 index 0000000..d344a38 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-reggae.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-reggae@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-reggae@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae.png new file mode 100644 index 0000000..0b0063e Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@2x.png new file mode 100644 index 0000000..0b1999f Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@3x.png new file mode 100644 index 0000000..6a99e22 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre25.imageset/genre-image-reggae@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/Contents.json new file mode 100644 index 0000000..02082b7 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-regional-mexican.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-regional-mexican@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-regional-mexican@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican.png new file mode 100644 index 0000000..6b9e3fc Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@2x.png new file mode 100644 index 0000000..0187860 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@3x.png new file mode 100644 index 0000000..c22d06d Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre26.imageset/genre-image-regional-mexican@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/Contents.json new file mode 100644 index 0000000..2dfa8ad --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-singer-songwriter.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-singer-songwriter@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-singer-songwriter@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter.png new file mode 100644 index 0000000..21d2348 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@2x.png new file mode 100644 index 0000000..b1bde2a Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@3x.png new file mode 100644 index 0000000..5e77dcd Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre27.imageset/genre-image-singer-songwriter@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/Contents.json new file mode 100644 index 0000000..a0f3238 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-smooth-jazz.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-smooth-jazz@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-smooth-jazz@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz.png new file mode 100644 index 0000000..8a4f830 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@2x.png new file mode 100644 index 0000000..501c0b3 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@3x.png new file mode 100644 index 0000000..ffb5678 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre28.imageset/genre-image-smooth-jazz@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/Contents.json new file mode 100644 index 0000000..1d2eb5c --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-smooth-pop.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-smooth-pop@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-smooth-pop@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop.png new file mode 100644 index 0000000..5e2068c Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@2x.png new file mode 100644 index 0000000..7d1339a Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@3x.png new file mode 100644 index 0000000..2e657ab Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre29.imageset/genre-image-smooth-pop@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/Contents.json new file mode 100644 index 0000000..573a385 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-blues.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-blues@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-blues@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues.png new file mode 100644 index 0000000..36aaa25 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@2x.png new file mode 100644 index 0000000..e6abbf2 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@3x.png new file mode 100644 index 0000000..661e921 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre3.imageset/genre-image-blues@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/Contents.json new file mode 100644 index 0000000..9a2674c --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-world-hits.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-world-hits@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-world-hits@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits.png new file mode 100644 index 0000000..9318df4 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@2x.png new file mode 100644 index 0000000..b6ace1a Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@3x.png new file mode 100644 index 0000000..72fa39c Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre30.imageset/genre-image-world-hits@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/Contents.json new file mode 100644 index 0000000..87e8856 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-christian.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-christian@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-christian@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian.png new file mode 100644 index 0000000..5a6ce2d Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@2x.png new file mode 100644 index 0000000..4bf917a Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@3x.png new file mode 100644 index 0000000..9fc8e29 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre4.imageset/genre-image-christian@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/Contents.json new file mode 100644 index 0000000..0481622 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-classic-alt.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-alt@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-alt@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt.png new file mode 100644 index 0000000..a3026f6 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@2x.png new file mode 100644 index 0000000..8fcde7e Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@3x.png new file mode 100644 index 0000000..24b35d4 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre5.imageset/genre-image-classic-alt@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/Contents.json new file mode 100644 index 0000000..1a94135 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-classic-country.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-country@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-country@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country.png new file mode 100644 index 0000000..9962388 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@2x.png new file mode 100644 index 0000000..d0ffe54 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@3x.png new file mode 100644 index 0000000..bce6eda Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre6.imageset/genre-image-classic-country@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/Contents.json new file mode 100644 index 0000000..636ae4e --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-classic-randb.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-randb@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-randb@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb.png new file mode 100644 index 0000000..ef46d9a Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@2x.png new file mode 100644 index 0000000..04b13e9 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@3x.png new file mode 100644 index 0000000..288edca Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre7.imageset/genre-image-classic-randb@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/Contents.json new file mode 100644 index 0000000..f9263e2 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-classic-rock.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-rock@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classic-rock@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock.png new file mode 100644 index 0000000..0773609 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@2x.png new file mode 100644 index 0000000..d2b92b8 Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@3x.png new file mode 100644 index 0000000..43e066f Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre8.imageset/genre-image-classic-rock@3x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/Contents.json new file mode 100644 index 0000000..3495ad1 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "genre-image-classical.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classical@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "genre-image-classical@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical.png new file mode 100644 index 0000000..8927b2f Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@2x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@2x.png new file mode 100644 index 0000000..d514c7f Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@2x.png differ diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@3x.png b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@3x.png new file mode 100644 index 0000000..47494db Binary files /dev/null and b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/genre9.imageset/genre-image-classical@3x.png differ diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/list.bullet.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/list.bullet.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/list.bullet.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/list.bullet.imageset/list.bullet.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/music.mic.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/music.mic.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/music.mic.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.mic.imageset/music.mic.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/music.quarternote.3.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/music.quarternote.3.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/music.quarternote.3.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/music.quarternote.3.imageset/music.quarternote.3.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/pause.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/pause.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/pause.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/pause.fill.imageset/pause.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/play.circle.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/play.circle.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/play.circle.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.circle.fill.imageset/play.circle.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/play.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/play.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/play.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/play.fill.imageset/play.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/plus.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/plus.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/plus.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/plus.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/plus.imageset/plus.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/plus.imageset/plus.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/plus.imageset/plus.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/plus.imageset/plus.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/quote.bubble.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/quote.bubble.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/quote.bubble.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/quote.bubble.imageset/quote.bubble.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/shuffle.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/shuffle.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/shuffle.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/shuffle.imageset/shuffle.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/speaker.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/speaker.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/speaker.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.fill.imageset/speaker.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/speaker.wave.3.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/speaker.wave.3.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/speaker.wave.3.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/speaker.wave.3.fill.imageset/speaker.wave.3.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/square.and.arrow.up.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/square.and.arrow.up.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/square.and.arrow.up.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/square.and.arrow.up.imageset/square.and.arrow.up.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/stop.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/stop.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/stop.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/stop.fill.imageset/stop.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/Contents.json b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/Contents.json similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/Contents.json rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/Contents.json diff --git a/LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/suit.heart.fill.svg b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/suit.heart.fill.svg similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/suit.heart.fill.svg rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Assets.xcassets/suit.heart.fill.imageset/suit.heart.fill.svg diff --git a/LNPopupControllerExample/LNPopupControllerExample/Base.lproj/Main.storyboard b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Base.lproj/Main.storyboard similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Base.lproj/Main.storyboard rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Base.lproj/Main.storyboard diff --git a/LNPopupControllerExample/LNPopupControllerExample/CustomMapBarViewController.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/CustomMapBarViewController.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/CustomMapBarViewController.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/CustomMapBarViewController.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/DemoAlbumTableViewController.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoAlbumTableViewController.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/DemoAlbumTableViewController.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoAlbumTableViewController.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/DemoGallery.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoGallery.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/DemoGallery.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoGallery.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/DemoGallery.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoGallery.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/DemoGallery.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoGallery.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/DemoMusicPlayerController.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoMusicPlayerController.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/DemoMusicPlayerController.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoMusicPlayerController.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/DemoPopupContentViewController.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoPopupContentViewController.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/DemoPopupContentViewController.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoPopupContentViewController.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/DemoPopupContentViewController.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoPopupContentViewController.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/DemoPopupContentViewController.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/DemoPopupContentViewController.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/FirstViewController.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/FirstViewController.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/FirstViewController.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/FirstViewController.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/FirstViewController.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/FirstViewController.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/FirstViewController.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/FirstViewController.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/HigherSearchBar.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/HigherSearchBar.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/HigherSearchBar.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/HigherSearchBar.swift diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/Info.plist b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Info.plist new file mode 100644 index 0000000..cd85e9f --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Info.plist @@ -0,0 +1,83 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + LNPopup + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 2.10.38 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + LNPopupExample + UISceneDelegateClassName + SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIRequiresFullScreen + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/IntroWebViewController.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/IntroWebViewController.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/IntroWebViewController.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/IntroWebViewController.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/IntroWebViewController.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/IntroWebViewController.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/IntroWebViewController.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/IntroWebViewController.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExample-Bridging-Header.h diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExample.entitlements b/LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExample.entitlements new file mode 100644 index 0000000..ee95ab7 --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExample.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + diff --git a/LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist b/LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist new file mode 100644 index 0000000..cf8232c --- /dev/null +++ b/LNPopupControllerExample_iOS12/LNPopupControllerExample/LNPopupControllerExampleNoPopup-Info.plist @@ -0,0 +1,81 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + LNPopup + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + LNPopupExample + UISceneDelegateClassName + SceneDelegate + UISceneStoryboardFile + Main + + + + + UILaunchStoryboardName + Main + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIRequiresFullScreen + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/LNPopupControllerExample/LNPopupControllerExample/LaunchScreen.storyboard b/LNPopupControllerExample_iOS12/LNPopupControllerExample/LaunchScreen.storyboard similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/LaunchScreen.storyboard rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/LaunchScreen.storyboard diff --git a/LNPopupControllerExample/LNPopupControllerExample/LocationsController.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/LocationsController.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/LocationsController.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/LocationsController.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/ManualLayoutCustomBarViewController.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/ManualLayoutCustomBarViewController.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/ManualLayoutCustomBarViewController.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/ManualLayoutCustomBarViewController.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/ManualLayoutScene.storyboard b/LNPopupControllerExample_iOS12/LNPopupControllerExample/ManualLayoutScene.storyboard similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/ManualLayoutScene.storyboard rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/ManualLayoutScene.storyboard diff --git a/LNPopupControllerExample/LNPopupControllerExample/MapScene.storyboard b/LNPopupControllerExample_iOS12/LNPopupControllerExample/MapScene.storyboard similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/MapScene.storyboard rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/MapScene.storyboard diff --git a/LNPopupControllerExample/LNPopupControllerExample/MapViewController.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/MapViewController.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/MapViewController.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/MapViewController.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/Music.storyboard b/LNPopupControllerExample_iOS12/LNPopupControllerExample/Music.storyboard similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/Music.storyboard rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/Music.storyboard diff --git a/LNPopupControllerExample/LNPopupControllerExample/MusicCell.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/MusicCell.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/MusicCell.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/MusicCell.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/NSObject+XcodeBugs.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/NSObject+XcodeBugs.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/NSObject+XcodeBugs.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/NSObject+XcodeBugs.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/NSObject+XcodeBugs.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/NSObject+XcodeBugs.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/NSObject+XcodeBugs.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/NSObject+XcodeBugs.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/PortraitTabBarController.swift b/LNPopupControllerExample_iOS12/LNPopupControllerExample/PortraitTabBarController.swift similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/PortraitTabBarController.swift rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/PortraitTabBarController.swift diff --git a/LNPopupControllerExample/LNPopupControllerExample/RandomColors.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/RandomColors.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/RandomColors.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/RandomColors.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/RandomColors.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/RandomColors.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/RandomColors.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/RandomColors.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/SceneDelegate.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/SceneDelegate.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/SceneDelegate.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/SceneDelegate.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/SceneDelegate.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/SceneDelegate.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/SceneDelegate.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/SceneDelegate.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/SettingsTableViewController.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/SettingsTableViewController.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/SettingsTableViewController.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/SettingsTableViewController.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/SettingsTableViewController.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/SettingsTableViewController.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/SettingsTableViewController.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/SettingsTableViewController.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/SplitViewController.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/SplitViewController.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/SplitViewController.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/SplitViewController.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/SplitViewController.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/SplitViewController.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/SplitViewController.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/SplitViewController.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/TOInsetGroupedTableView.h b/LNPopupControllerExample_iOS12/LNPopupControllerExample/TOInsetGroupedTableView.h similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/TOInsetGroupedTableView.h rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/TOInsetGroupedTableView.h diff --git a/LNPopupControllerExample/LNPopupControllerExample/TOInsetGroupedTableView.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/TOInsetGroupedTableView.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/TOInsetGroupedTableView.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/TOInsetGroupedTableView.m diff --git a/LNPopupControllerExample/LNPopupControllerExample/main.m b/LNPopupControllerExample_iOS12/LNPopupControllerExample/main.m similarity index 100% rename from LNPopupControllerExample/LNPopupControllerExample/main.m rename to LNPopupControllerExample_iOS12/LNPopupControllerExample/main.m diff --git a/LNPopupSettings b/LNPopupSettings index 8ab9516..6d5428f 160000 --- a/LNPopupSettings +++ b/LNPopupSettings @@ -1 +1 @@ -Subproject commit 8ab95168805498f3cce5eb77064abf19d93a56d2 +Subproject commit 6d5428faa04677a8e6d80fdba8b71b0cc4316aaa