├── DynamicCell.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── mohannad.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── DynamicCell.xcworkspace ├── contents.xcworkspacedata ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── mohannad.xcuserdatad │ └── xcdebugger │ └── Breakpoints_v2.xcbkptlist ├── DynamicCell ├── Controllers │ ├── CommentsController.swift │ ├── FeedsController.swift │ └── MainController.swift ├── Info.plist ├── Models │ ├── Comment.swift │ └── Photo.swift ├── Others │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── 90.imageset │ │ │ ├── 90.jpeg │ │ │ └── Contents.json │ │ ├── 91.imageset │ │ │ ├── 91.jpeg │ │ │ └── Contents.json │ │ ├── 92.imageset │ │ │ ├── 92.jpeg │ │ │ └── Contents.json │ │ ├── 93.imageset │ │ │ ├── 99.jpeg │ │ │ └── Contents.json │ │ ├── 94.imageset │ │ │ ├── 94.jpeg │ │ │ └── Contents.json │ │ ├── 95.imageset │ │ │ ├── 95.jpeg │ │ │ └── Contents.json │ │ ├── 96.imageset │ │ │ ├── 96.jpeg │ │ │ └── Contents.json │ │ ├── 97.imageset │ │ │ ├── 97.jpeg │ │ │ └── Contents.json │ │ ├── 98.imageset │ │ │ ├── 98.jpeg │ │ │ └── Contents.json │ │ ├── 99.imageset │ │ │ ├── 93.jpeg │ │ │ └── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ └── SceneDelegate.swift ├── Utilities │ ├── ApiService.swift │ ├── CommentFlowLayout.swift │ ├── Constants.swift │ ├── Extentions.swift │ └── PinterestLayout.swift └── Views │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Comments.storyboard │ ├── CustomCells │ ├── CommentCell.swift │ └── FeedCell.swift │ └── Feeds.storyboard ├── DynamicCellTests ├── DynamicCellTests.swift └── Info.plist ├── DynamicCellUITests ├── DynamicCellUITests.swift └── Info.plist ├── Podfile ├── Podfile.lock ├── Pods ├── Fakery │ ├── LICENSE.md │ ├── README.md │ ├── README.md.orig │ └── Sources │ │ └── Fakery │ │ ├── Config.swift │ │ ├── Data │ │ ├── Parser.swift │ │ └── Provider.swift │ │ ├── Extensions │ │ ├── ArrayExtension.swift │ │ └── StringExtensions.swift │ │ ├── Faker.swift │ │ ├── Generators │ │ ├── Address.swift │ │ ├── App.swift │ │ ├── Bank.swift │ │ ├── Business.swift │ │ ├── Car.swift │ │ ├── Cat.swift │ │ ├── Commerce.swift │ │ ├── Company.swift │ │ ├── Date.swift │ │ ├── Gender.swift │ │ ├── Generator.swift │ │ ├── Ham.swift │ │ ├── Hobbit.swift │ │ ├── House.swift │ │ ├── Internet.swift │ │ ├── Lorem.swift │ │ ├── Name.swift │ │ ├── Number.swift │ │ ├── PhoneNumber.swift │ │ ├── ProgrammingLanguage.swift │ │ ├── Team.swift │ │ ├── Vehicle.swift │ │ └── Zelda.swift │ │ └── Resources │ │ └── Locales │ │ ├── de-AT.json │ │ ├── de-CH.json │ │ ├── de.json │ │ ├── en-AU.json │ │ ├── en-CA.json │ │ ├── en-GB.json │ │ ├── en-IND.json │ │ ├── en-TEST.json │ │ ├── en-US.json │ │ ├── en.json │ │ ├── es.json │ │ ├── fa.json │ │ ├── fr.json │ │ ├── it.json │ │ ├── ja.json │ │ ├── ko.json │ │ ├── nb-NO.json │ │ ├── nl.json │ │ ├── pl.json │ │ ├── pt-BR.json │ │ ├── ru.json │ │ ├── sk.json │ │ ├── sv.json │ │ ├── tr-TR.json │ │ ├── uk.json │ │ ├── zh-CN.json │ │ └── zh-TW.json ├── Kingfisher │ ├── LICENSE │ ├── README.md │ └── Sources │ │ ├── Cache │ │ ├── CacheSerializer.swift │ │ ├── DiskStorage.swift │ │ ├── FormatIndicatedCacheSerializer.swift │ │ ├── ImageCache.swift │ │ ├── MemoryStorage.swift │ │ └── Storage.swift │ │ ├── Extensions │ │ ├── ImageView+Kingfisher.swift │ │ ├── NSButton+Kingfisher.swift │ │ ├── NSTextAttachment+Kingfisher.swift │ │ ├── TVMonogramView+Kingfisher.swift │ │ ├── UIButton+Kingfisher.swift │ │ └── WKInterfaceImage+Kingfisher.swift │ │ ├── General │ │ ├── ImageSource │ │ │ ├── AVAssetImageDataProvider.swift │ │ │ ├── ImageDataProvider.swift │ │ │ ├── Resource.swift │ │ │ └── Source.swift │ │ ├── KF.swift │ │ ├── KFOptionsSetter.swift │ │ ├── Kingfisher.swift │ │ ├── KingfisherError.swift │ │ ├── KingfisherManager.swift │ │ └── KingfisherOptionsInfo.swift │ │ ├── Image │ │ ├── Filter.swift │ │ ├── GIFAnimatedImage.swift │ │ ├── Image.swift │ │ ├── ImageDrawing.swift │ │ ├── ImageFormat.swift │ │ ├── ImageProcessor.swift │ │ ├── ImageProgressive.swift │ │ ├── ImageTransition.swift │ │ └── Placeholder.swift │ │ ├── Kingfisher.h │ │ ├── Networking │ │ ├── AuthenticationChallengeResponsable.swift │ │ ├── ImageDataProcessor.swift │ │ ├── ImageDownloader.swift │ │ ├── ImageDownloaderDelegate.swift │ │ ├── ImageModifier.swift │ │ ├── ImagePrefetcher.swift │ │ ├── RedirectHandler.swift │ │ ├── RequestModifier.swift │ │ ├── RetryStrategy.swift │ │ ├── SessionDataTask.swift │ │ └── SessionDelegate.swift │ │ ├── SwiftUI │ │ ├── ImageBinder.swift │ │ ├── KFImage.swift │ │ └── KFImageOptions.swift │ │ ├── Utility │ │ ├── Box.swift │ │ ├── CallbackQueue.swift │ │ ├── Delegate.swift │ │ ├── ExtensionHelpers.swift │ │ ├── Result.swift │ │ ├── Runtime.swift │ │ ├── SizeExtensions.swift │ │ └── String+MD5.swift │ │ └── Views │ │ ├── AnimatedImageView.swift │ │ └── Indicator.swift ├── Manifest.lock ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── mohannad.xcuserdatad │ │ └── xcschemes │ │ ├── Fakery-Faker.xcscheme │ │ ├── Fakery.xcscheme │ │ ├── Kingfisher.xcscheme │ │ ├── Pods-DynamicCell-DynamicCellUITests.xcscheme │ │ ├── Pods-DynamicCell.xcscheme │ │ ├── Pods-DynamicCellTests.xcscheme │ │ └── xcschememanagement.plist └── Target Support Files │ ├── Fakery │ ├── Fakery-Info.plist │ ├── Fakery-dummy.m │ ├── Fakery-prefix.pch │ ├── Fakery-umbrella.h │ ├── Fakery.debug.xcconfig │ ├── Fakery.modulemap │ ├── Fakery.release.xcconfig │ └── ResourceBundle-Faker-Fakery-Info.plist │ ├── Kingfisher │ ├── Kingfisher-Info.plist │ ├── Kingfisher-dummy.m │ ├── Kingfisher-prefix.pch │ ├── Kingfisher-umbrella.h │ ├── Kingfisher.debug.xcconfig │ ├── Kingfisher.modulemap │ └── Kingfisher.release.xcconfig │ ├── Pods-DynamicCell-DynamicCellUITests │ ├── Pods-DynamicCell-DynamicCellUITests-Info.plist │ ├── Pods-DynamicCell-DynamicCellUITests-acknowledgements.markdown │ ├── Pods-DynamicCell-DynamicCellUITests-acknowledgements.plist │ ├── Pods-DynamicCell-DynamicCellUITests-dummy.m │ ├── Pods-DynamicCell-DynamicCellUITests-frameworks-Debug-input-files.xcfilelist │ ├── Pods-DynamicCell-DynamicCellUITests-frameworks-Debug-output-files.xcfilelist │ ├── Pods-DynamicCell-DynamicCellUITests-frameworks-Release-input-files.xcfilelist │ ├── Pods-DynamicCell-DynamicCellUITests-frameworks-Release-output-files.xcfilelist │ ├── Pods-DynamicCell-DynamicCellUITests-frameworks.sh │ ├── Pods-DynamicCell-DynamicCellUITests-umbrella.h │ ├── Pods-DynamicCell-DynamicCellUITests.debug.xcconfig │ ├── Pods-DynamicCell-DynamicCellUITests.modulemap │ └── Pods-DynamicCell-DynamicCellUITests.release.xcconfig │ ├── Pods-DynamicCell │ ├── Pods-DynamicCell-Info.plist │ ├── Pods-DynamicCell-acknowledgements.markdown │ ├── Pods-DynamicCell-acknowledgements.plist │ ├── Pods-DynamicCell-dummy.m │ ├── Pods-DynamicCell-frameworks-Debug-input-files.xcfilelist │ ├── Pods-DynamicCell-frameworks-Debug-output-files.xcfilelist │ ├── Pods-DynamicCell-frameworks-Release-input-files.xcfilelist │ ├── Pods-DynamicCell-frameworks-Release-output-files.xcfilelist │ ├── Pods-DynamicCell-frameworks.sh │ ├── Pods-DynamicCell-umbrella.h │ ├── Pods-DynamicCell.debug.xcconfig │ ├── Pods-DynamicCell.modulemap │ └── Pods-DynamicCell.release.xcconfig │ └── Pods-DynamicCellTests │ ├── Pods-DynamicCellTests-Info.plist │ ├── Pods-DynamicCellTests-acknowledgements.markdown │ ├── Pods-DynamicCellTests-acknowledgements.plist │ ├── Pods-DynamicCellTests-dummy.m │ ├── Pods-DynamicCellTests-umbrella.h │ ├── Pods-DynamicCellTests.debug.xcconfig │ ├── Pods-DynamicCellTests.modulemap │ └── Pods-DynamicCellTests.release.xcconfig └── README.md /DynamicCell.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DynamicCell.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DynamicCell.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DynamicCell.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 6 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /DynamicCell.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /DynamicCell.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DynamicCell.xcworkspace/xcuserdata/mohannad.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /DynamicCell/Controllers/CommentsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentsController.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 29.03.2021. 6 | // 7 | 8 | import UIKit 9 | import Fakery 10 | 11 | class CommentsController: UIViewController { 12 | 13 | 14 | @IBOutlet weak var commentColllection: UICollectionView! 15 | 16 | let commentFlowLayout = CommentFlowLayout() 17 | 18 | private var comments = [Comment]() 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | buildComments() 23 | configure() 24 | 25 | } 26 | 27 | 28 | 29 | func configure () { 30 | 31 | commentColllection.dataSource = self 32 | commentColllection.register(CommentCell.self, forCellWithReuseIdentifier: "cell") 33 | commentFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize 34 | commentFlowLayout.minimumInteritemSpacing = 10 35 | commentFlowLayout.minimumLineSpacing = 10 36 | commentColllection.collectionViewLayout = commentFlowLayout 37 | commentColllection.contentInsetAdjustmentBehavior = .always 38 | commentColllection.reloadData() 39 | } 40 | 41 | 42 | func buildComments(){ 43 | 44 | let faker = Faker(locale: "nb-NO") 45 | for i in 0...9 { 46 | let randomInt = Int(arc4random_uniform(6) + 1) 47 | var info = Comment(owner: faker.name.name(), id: UUID().uuidString, message: faker.lorem.sentences(amount: 5), ownerPhoto: "9\(i)") 48 | 49 | comments.append(info) 50 | 51 | } 52 | 53 | } 54 | } 55 | 56 | 57 | 58 | extension CommentsController : UICollectionViewDataSource { 59 | 60 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 61 | return comments.count 62 | } 63 | 64 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 65 | 66 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CommentCell 67 | 68 | cell.comment = comments[indexPath.row] 69 | 70 | return cell 71 | } 72 | 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /DynamicCell/Controllers/FeedsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FeedsController.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 29.03.2021. 6 | // 7 | 8 | import UIKit 9 | import Fakery 10 | 11 | class FeedsController: UIViewController { 12 | 13 | @IBOutlet weak var feedCollection: UICollectionView! 14 | 15 | var photos = [Photo]() 16 | 17 | var headers = [String]() 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | buildHeaders() 22 | configure() 23 | 24 | } 25 | 26 | 27 | func configure(){ 28 | 29 | let layout = PinterestLayout() 30 | layout.delegate = self 31 | 32 | feedCollection.register(FeedCell.self, forCellWithReuseIdentifier: "FeedCell") 33 | feedCollection.dataSource = self 34 | feedCollection.collectionViewLayout = layout 35 | feedCollection.toggleActivityIndicator() 36 | 37 | ApiService.shared.getPhotos { (res) in 38 | 39 | if let photos = res { 40 | 41 | DispatchQueue.main.async { 42 | 43 | self.feedCollection.toggleActivityIndicator() 44 | 45 | self.photos = photos 46 | 47 | self.feedCollection.reloadData() 48 | } 49 | } 50 | } 51 | } 52 | 53 | func buildHeaders(){ 54 | 55 | let faker = Faker(locale: "nb-NO") 56 | for i in 0...50 { 57 | let randomInt = Int(arc4random_uniform(13) + 2) 58 | let text = faker.lorem.words(amount: randomInt) 59 | headers.append(text) 60 | } 61 | } 62 | } 63 | 64 | extension FeedsController : UICollectionViewDataSource , UICollectionViewDelegate { 65 | 66 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 67 | return photos.count 68 | } 69 | 70 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 71 | 72 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeedCell", for: indexPath) as! FeedCell 73 | 74 | cell.info = photos[indexPath.row] 75 | 76 | cell.descLab.text = headers[indexPath.row] 77 | 78 | return cell 79 | 80 | } 81 | 82 | } 83 | 84 | extension FeedsController : PinterestLayoutDelegate { 85 | 86 | func collectionView(_ collectionView: UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath, cellWidth: CGFloat) -> CGFloat { 87 | 88 | let imgHeight = calculateImageHeight(sourceImage: photos[indexPath.row] , scaledToWidth: cellWidth) 89 | 90 | let textHeight = requiredHeight(text: headers[indexPath.row], cellWidth: (cellWidth - 10)) 91 | 92 | return (imgHeight + textHeight + 10) 93 | 94 | } 95 | 96 | func calculateImageHeight (sourceImage:Photo, scaledToWidth: CGFloat) -> CGFloat { 97 | let oldWidth = CGFloat( sourceImage.width) 98 | let scaleFactor = scaledToWidth / oldWidth 99 | let newHeight = CGFloat(sourceImage.height) * scaleFactor 100 | return newHeight 101 | } 102 | 103 | func requiredHeight(text:String , cellWidth : CGFloat) -> CGFloat { 104 | 105 | let font = UIFont(name: "Helvetica", size: 16.0) 106 | let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: cellWidth, height: .greatestFiniteMagnitude)) 107 | label.numberOfLines = 0 108 | label.lineBreakMode = .byWordWrapping 109 | label.font = font 110 | label.text = text 111 | label.sizeToFit() 112 | return label.frame.height 113 | 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /DynamicCell/Controllers/MainController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 27.03.2021. 6 | // 7 | 8 | import UIKit 9 | import Fakery 10 | 11 | class MainController: UIViewController { 12 | 13 | 14 | 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | 20 | 21 | // Do any additional setup after loading the view. 22 | } 23 | 24 | 25 | 26 | 27 | 28 | 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /DynamicCell/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UISupportedInterfaceOrientations~ipad 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationPortraitUpsideDown 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /DynamicCell/Models/Comment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Comment.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 29.03.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Comment : Codable { 11 | var owner : String 12 | var id : String 13 | var message : String 14 | var ownerPhoto : String 15 | 16 | } 17 | -------------------------------------------------------------------------------- /DynamicCell/Models/Photo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Photo.swift 3 | // MVVMArchitecture 4 | // 5 | // Created by Mohannad on 26.03.2021. 6 | // 7 | 8 | import UIKit 9 | 10 | 11 | class Photo : Codable { 12 | var id : String 13 | var width : Int 14 | var height : Int 15 | var url : String 16 | var download_url : String 17 | } 18 | -------------------------------------------------------------------------------- /DynamicCell/Others/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 27.03.2021. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/90.imageset/90.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/90.imageset/90.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/90.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "90.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/91.imageset/91.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/91.imageset/91.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/91.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "91.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/92.imageset/92.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/92.imageset/92.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/92.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "92.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/93.imageset/99.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/93.imageset/99.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/93.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "99.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/94.imageset/94.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/94.imageset/94.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/94.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "94.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/95.imageset/95.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/95.imageset/95.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/95.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "95.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/96.imageset/96.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/96.imageset/96.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/96.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "96.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/97.imageset/97.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/97.imageset/97.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/97.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "97.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/98.imageset/98.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/98.imageset/98.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/98.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "98.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/99.imageset/93.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MohannadBakbouk/DynamicCell/91ccccd6ca3dca6b02224a264020f89763f6d872/DynamicCell/Others/Assets.xcassets/99.imageset/93.jpeg -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/99.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "93.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /DynamicCell/Others/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /DynamicCell/Others/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 27.03.2021. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /DynamicCell/Utilities/ApiService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ApiService.swift 3 | // MVVMArchitecture 4 | // 5 | // Created by Mohannad on 15.02.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | class ApiService : NSObject { 12 | 13 | static let shared = ApiService() 14 | 15 | 16 | 17 | 18 | func getPhotos(completion : @escaping ([Photo]?)->()) { 19 | 20 | 21 | var urlComp = URLComponents(string:"\(Constants.identifiers.photosApi)")! 22 | 23 | urlComp.queryItems = [URLQueryItem(name: "page", value: "1" ), 24 | URLQueryItem(name: "limit", value: "50")] 25 | 26 | var request = URLRequest(url: urlComp.url!) 27 | 28 | request.httpMethod = "Get" 29 | 30 | request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type") 31 | 32 | request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept") 33 | 34 | let task = URLSession.shared.dataTask(with: request) { (data, response, error) in 35 | 36 | guard let data = data , error == nil else { 37 | print("error while fetching feeds \(error)") 38 | completion(nil) 39 | return 40 | } 41 | 42 | let result = try? JSONDecoder().decode([Photo].self, from: data) 43 | 44 | completion(result) 45 | } 46 | 47 | task.resume() 48 | 49 | 50 | } 51 | 52 | 53 | 54 | 55 | } 56 | 57 | 58 | -------------------------------------------------------------------------------- /DynamicCell/Utilities/CommentFlowLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentFlowLayout.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 29.03.2021. 6 | // 7 | 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | final class CommentFlowLayout : UICollectionViewFlowLayout { 13 | 14 | override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 15 | let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ $0.copy() } as? [UICollectionViewLayoutAttributes] 16 | layoutAttributesObjects?.forEach({ layoutAttributes in 17 | if layoutAttributes.representedElementCategory == .cell { 18 | if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame { 19 | layoutAttributes.frame = newFrame 20 | } 21 | } 22 | }) 23 | return layoutAttributesObjects 24 | } 25 | 26 | 27 | override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 28 | 29 | 30 | guard let collectionView = collectionView else { 31 | fatalError() 32 | } 33 | guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else { 34 | return nil 35 | } 36 | 37 | layoutAttributes.frame.origin.x = sectionInset.left 38 | layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right 39 | return layoutAttributes 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /DynamicCell/Utilities/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // MVVMArchitecture 4 | // 5 | // Created by Mohannad on 15.02.2021. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Constants { 11 | 12 | struct identifiers { 13 | static let apiUrl = "https://dummyapi.io/data/api/" 14 | static let apiKey = "5fa160451843ad228d0a1c7c" 15 | static let photosApi = "https://picsum.photos/v2/list" 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /DynamicCell/Utilities/PinterestLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewAutoSizingFlowLayout.swift 3 | // MVVMArchitecture 4 | // 5 | // Created by Mohannad on 17.03.2021. 6 | // 7 | 8 | import UIKit 9 | 10 | 11 | protocol PinterestLayoutDelegate: AnyObject { 12 | func collectionView(_ collectionView: UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath , cellWidth : CGFloat ) -> CGFloat 13 | } 14 | 15 | class PinterestLayout: UICollectionViewLayout { 16 | 17 | weak var delegate: PinterestLayoutDelegate? 18 | private let numberOfColumns = 2 19 | private let cellPadding: CGFloat = 6 20 | private var cache: [UICollectionViewLayoutAttributes] = [] 21 | private var contentHeight: CGFloat = 0 22 | private var contentWidth: CGFloat { 23 | guard let collectionView = collectionView else { 24 | return 0 25 | } 26 | let insets = collectionView.contentInset 27 | return collectionView.bounds.width - (insets.left + insets.right) 28 | } 29 | 30 | override var collectionViewContentSize: CGSize { 31 | return CGSize(width: contentWidth, height: contentHeight) 32 | } 33 | 34 | override func prepare() { 35 | guard cache.isEmpty == true,let collectionView = collectionView else { 36 | return 37 | } 38 | let columnWidth = contentWidth / CGFloat(numberOfColumns) 39 | var xOffset: [CGFloat] = [] 40 | for column in 0.. [UICollectionViewLayoutAttributes]? { 65 | var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = [] 66 | 67 | // Loop through the cache and look for items in the rect 68 | for attributes in cache { 69 | if attributes.frame.intersects(rect) { 70 | visibleLayoutAttributes.append(attributes) 71 | } 72 | } 73 | return visibleLayoutAttributes 74 | } 75 | 76 | override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 77 | return cache[indexPath.item] 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /DynamicCell/Views/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /DynamicCell/Views/Comments.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /DynamicCell/Views/CustomCells/CommentCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentCell.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 29.03.2021. 6 | // 7 | 8 | import UIKit 9 | 10 | class CommentCell: UICollectionViewCell { 11 | 12 | var comment : Comment! { 13 | 14 | didSet { 15 | 16 | messageLab.text = comment.message //comment.message 17 | nameLab.text = comment.owner 18 | img.image = UIImage(named: comment.ownerPhoto) 19 | 20 | 21 | } 22 | } 23 | 24 | var messageLab : UILabel = { 25 | let lab = UILabel() 26 | lab.text = "" 27 | lab.numberOfLines = 10 28 | lab.textColor = .white 29 | return lab 30 | }() 31 | 32 | var nameLab : UILabel = { 33 | let lab = UILabel() 34 | lab.text = "Mohannad bakbouk" 35 | lab.textColor = .systemGray6 36 | lab.numberOfLines = 1 37 | return lab 38 | }() 39 | 40 | var img : UIImageView = { 41 | let img = UIImageView() 42 | img.backgroundColor = .gray 43 | img.contentMode = .scaleAspectFill 44 | img.clipsToBounds = true 45 | img.kf.indicatorType = .activity 46 | img.layer.cornerRadius = 25 47 | return img 48 | }() 49 | 50 | var container : UIView = { 51 | let view = UIView() 52 | view.clipsToBounds = true 53 | //view.backgroundColor = .systemGray6 54 | view.backgroundColor = .mainColor 55 | view.layer.cornerRadius = 8 56 | return view 57 | }() 58 | 59 | override init(frame: CGRect) { 60 | super.init(frame: frame) 61 | setupViews() 62 | } 63 | 64 | required init?(coder: NSCoder) { 65 | super.init(coder: coder) 66 | setupViews() 67 | } 68 | 69 | func setupViews(){ 70 | 71 | contentView.addSubview(img) 72 | contentView.addSubview(container) 73 | container.addSubview(nameLab) 74 | container.addSubview(messageLab) 75 | 76 | img.anchor(top: contentView.topAnchor, paddingTop: 5, bottom: nil, paddingBottom: 0, left: contentView.leadingAnchor, paddingLeft: 10, right: nil, paddingRight: 0, width: 50, height: 50) 77 | 78 | container.anchor(top: contentView.topAnchor, paddingTop: 0, bottom: contentView.bottomAnchor, paddingBottom: -10, left: img.trailingAnchor, paddingLeft: 10, right: contentView.trailingAnchor, paddingRight: -10, width: 0, height: 0) 79 | 80 | 81 | nameLab.anchor(top: container.topAnchor, paddingTop: 10, bottom: nil, paddingBottom: 0, left: container.leadingAnchor, paddingLeft: 10, right: container.trailingAnchor, paddingRight: -10, width: 0, height: 0) 82 | 83 | messageLab.anchor(top: nameLab.bottomAnchor, paddingTop: 10, bottom: container.bottomAnchor, paddingBottom: -5, left: container.leadingAnchor, paddingLeft: 10, right: container.trailingAnchor, paddingRight: -10, width: 0, height: 0) 84 | 85 | 86 | } 87 | 88 | 89 | override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { 90 | let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0) 91 | layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) 92 | return layoutAttributes 93 | } 94 | 95 | } 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /DynamicCell/Views/CustomCells/FeedCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FeedCell.swift 3 | // DynamicCell 4 | // 5 | // Created by Mohannad on 29.03.2021. 6 | // 7 | 8 | 9 | import UIKit 10 | import Kingfisher 11 | 12 | class FeedCell: UICollectionViewCell { 13 | 14 | var img : UIImageView = { 15 | let img = UIImageView() 16 | img.backgroundColor = .gray 17 | img.contentMode = .scaleAspectFill 18 | img.clipsToBounds = true 19 | img.translatesAutoresizingMaskIntoConstraints = false 20 | img.setContentHuggingPriority(.defaultLow, for: .vertical) 21 | return img 22 | }() 23 | 24 | var descLab : UILabel = { 25 | let lab = UILabel() 26 | lab.textColor = .white 27 | lab.numberOfLines = 0 28 | lab.lineBreakMode = .byWordWrapping 29 | lab.translatesAutoresizingMaskIntoConstraints = false 30 | lab.font = UIFont(name: "Helvetica", size: 16) 31 | lab.setContentHuggingPriority(.defaultHigh, for: .vertical) 32 | return lab 33 | }() 34 | 35 | var info : Photo? { 36 | didSet { 37 | assignPhoto() 38 | } 39 | } 40 | 41 | override func layoutSubviews() { 42 | super.layoutSubviews() 43 | setupViews() 44 | setupConstraints() 45 | } 46 | 47 | override init(frame: CGRect) { 48 | super.init(frame: frame) 49 | } 50 | 51 | required init?(coder: NSCoder) { 52 | super.init(coder: coder) 53 | } 54 | 55 | override func prepareForReuse() { 56 | super.prepareForReuse() 57 | info = nil 58 | img.removeFromSuperview() 59 | descLab.removeFromSuperview() 60 | 61 | } 62 | 63 | deinit { 64 | info = nil 65 | } 66 | 67 | 68 | func setupViews(){ 69 | 70 | layer.borderWidth = 1 71 | layer.borderColor = UIColor.lightGray.cgColor 72 | backgroundColor = .mainColor 73 | contentView.addSubview(img) 74 | contentView.addSubview(descLab) 75 | 76 | } 77 | 78 | func setupConstraints(){ 79 | img.anchor(top: contentView.topAnchor, paddingTop: 0, bottom: nil, paddingBottom: 0, left: contentView.leadingAnchor, paddingLeft: 0, right: contentView.trailingAnchor, paddingRight: 0, width: 0, height: 0) 80 | 81 | descLab.anchor(top: img.bottomAnchor , paddingTop: 5, bottom: contentView.bottomAnchor, paddingBottom: -5, left: contentView.leadingAnchor, paddingLeft: 5, right: contentView.trailingAnchor, paddingRight: -5, width: 0, height: 0) 82 | } 83 | 84 | func assignPhoto(){ 85 | 86 | guard let data = info else { 87 | return 88 | } 89 | 90 | img.kf.setImage(with: URL(string: data.download_url)!) { res in 91 | if case .success(let value) = res { 92 | ImageCache.default.store(value.image, forKey: data.download_url) 93 | 94 | } 95 | } 96 | } 97 | 98 | } 99 | 100 | -------------------------------------------------------------------------------- /DynamicCell/Views/Feeds.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /DynamicCellTests/DynamicCellTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicCellTests.swift 3 | // DynamicCellTests 4 | // 5 | // Created by Mohannad on 27.03.2021. 6 | // 7 | 8 | import XCTest 9 | @testable import DynamicCell 10 | 11 | class DynamicCellTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | } 25 | 26 | func testPerformanceExample() throws { 27 | // This is an example of a performance test case. 28 | self.measure { 29 | // Put the code you want to measure the time of here. 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /DynamicCellTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /DynamicCellUITests/DynamicCellUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicCellUITests.swift 3 | // DynamicCellUITests 4 | // 5 | // Created by Mohannad on 27.03.2021. 6 | // 7 | 8 | import XCTest 9 | 10 | class DynamicCellUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use recording to get started writing UI tests. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | func testLaunchPerformance() throws { 35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 36 | // This measures how long it takes to launch your application. 37 | measure(metrics: [XCTApplicationLaunchMetric()]) { 38 | XCUIApplication().launch() 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DynamicCellUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '14.0' 3 | 4 | target 'DynamicCell' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for DynamicCell 9 | pod 'Kingfisher', '~> 6.0' 10 | pod 'Fakery' 11 | 12 | target 'DynamicCellTests' do 13 | inherit! :search_paths 14 | # Pods for testing 15 | 16 | end 17 | 18 | target 'DynamicCellUITests' do 19 | # Pods for testing 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Fakery (5.1.0) 3 | - Kingfisher (6.0.1) 4 | 5 | DEPENDENCIES: 6 | - Fakery 7 | - Kingfisher (~> 6.0) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - Fakery 12 | - Kingfisher 13 | 14 | SPEC CHECKSUMS: 15 | Fakery: a90caff00ca5cacde6c161c3eafc72314a03d34d 16 | Kingfisher: adde87a4f74f6a3845395769354efff593581740 17 | 18 | PODFILE CHECKSUM: 2e75b4b78d18cf325281d383317394c9eb3d64ac 19 | 20 | COCOAPODS: 1.10.0 21 | -------------------------------------------------------------------------------- /Pods/Fakery/LICENSE.md: -------------------------------------------------------------------------------- 1 | Licensed under the **MIT** license 2 | 3 | > Copyright (c) 2015 Vadym Markov 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Config.swift: -------------------------------------------------------------------------------- 1 | public struct Config { 2 | public static let defaultLocale: String = "en" 3 | public static let pathExtension: String = "json" 4 | public static var dirPath: String = "Resources/Locales" 5 | public static var dirFrameworkPath: String = "" 6 | public static var dirResourcePath: String = "" 7 | } 8 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Data/Parser.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public final class Parser { 4 | public var locale: String { 5 | didSet { 6 | if locale != oldValue { 7 | loadData(forLocale: locale) 8 | } 9 | } 10 | } 11 | 12 | private var data = [String: Any]() 13 | let provider: Provider 14 | 15 | // MARK: - Initialization 16 | 17 | public init(locale: String = Config.defaultLocale) { 18 | self.locale = locale 19 | provider = Provider() 20 | loadData(forLocale: locale) 21 | 22 | if locale != Config.defaultLocale { 23 | loadData(forLocale: Config.defaultLocale) 24 | } 25 | } 26 | 27 | // MARK: - Parsing 28 | 29 | public func fetch(_ key: String) -> String { 30 | var parsed = "" 31 | 32 | guard let keyData = fetchRaw(key) else { 33 | return parsed 34 | } 35 | 36 | let subject = getSubject(key) 37 | 38 | if let value = keyData as? String { 39 | parsed = value 40 | } else if let array = keyData as? [String], let item = array.random() { 41 | parsed = item 42 | } 43 | 44 | if parsed.range(of: "#{") != nil { 45 | parsed = parse(parsed, forSubject: subject) 46 | } 47 | 48 | return parsed 49 | } 50 | 51 | public func fetchRaw(_ key: String) -> Any? { 52 | let result = fetchRaw(key, forLocale: locale) 53 | 54 | guard locale != Config.defaultLocale else { 55 | return result 56 | } 57 | 58 | return result ?? fetchRaw(key, forLocale: Config.defaultLocale) 59 | } 60 | 61 | func parse(_ template: String, forSubject subject: String) -> String { 62 | var text = "" 63 | let string = NSString(string: template) 64 | var regex: NSRegularExpression 65 | 66 | do { 67 | try regex = NSRegularExpression(pattern: "(\\(?)#\\{([A-Za-z]+\\.)?([^\\}]+)\\}([^#]+)?", 68 | options: .caseInsensitive) 69 | 70 | let matches = regex.matches(in: template, 71 | options: .reportCompletion, 72 | range: NSRange(location: 0, length: string.length)) 73 | 74 | guard !matches.isEmpty else { 75 | return template 76 | } 77 | 78 | for match in matches { 79 | if match.numberOfRanges < 4 { 80 | continue 81 | } 82 | 83 | let prefixRange = match.range(at: 1) 84 | let subjectRange = match.range(at: 2) 85 | let methodRange = match.range(at: 3) 86 | let otherRange = match.range(at: 4) 87 | 88 | if prefixRange.length > 0 { 89 | text += string.substring(with: prefixRange) 90 | } 91 | 92 | var subjectWithDot = subject + "." 93 | 94 | if subjectRange.length > 0 { 95 | subjectWithDot = string.substring(with: subjectRange) 96 | } 97 | 98 | if methodRange.length > 0 { 99 | let key = subjectWithDot.lowercased() + string.substring(with: methodRange) 100 | text += fetch(key) 101 | } 102 | 103 | if otherRange.length > 0 { 104 | text += string.substring(with: otherRange) 105 | } 106 | } 107 | } catch {} 108 | 109 | return text 110 | } 111 | 112 | private func fetchRaw(_ key: String, forLocale locale: String) -> Any? { 113 | let parts = key.components(separatedBy: ".") 114 | 115 | guard let localeData = data[locale] as? [String: Any], 116 | var parsed = localeData["faker"] as? [String: Any], 117 | !parts.isEmpty else { return nil } 118 | 119 | var result: Any? 120 | 121 | for part in parts { 122 | guard let parsedPart = parsed[part] as? [String: Any] else { 123 | result = parsed[part] 124 | continue 125 | } 126 | 127 | parsed = parsedPart 128 | result = parsedPart 129 | } 130 | 131 | return result 132 | } 133 | 134 | private func getSubject(_ key: String) -> String { 135 | var subject: String = "" 136 | let parts = key.components(separatedBy: ".") 137 | 138 | if !parts.isEmpty { 139 | subject = parts[0] 140 | } 141 | 142 | return subject 143 | } 144 | 145 | // MARK: - Data loading 146 | 147 | private func loadData(forLocale locale: String) { 148 | guard let localeData = provider.dataForLocale(locale), 149 | let parsedData = try? JSONSerialization.jsonObject(with: localeData, options: .allowFragments), 150 | let json = parsedData as? [String: Any], 151 | let localeJson = json[locale] else { 152 | print("JSON file for '\(locale)' locale was not found.") 153 | return 154 | } 155 | 156 | data[locale] = localeJson 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Data/Provider.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public final class Provider { 4 | var translations: [String: Data] = [:] 5 | 6 | // MARK: - Locale data 7 | 8 | public func dataForLocale(_ locale: String) -> Data? { 9 | var translation: Data? 10 | 11 | if let translationData = translations[locale] { 12 | translation = translationData 13 | } else { 14 | #if SWIFT_PACKAGE 15 | let bundle = Bundle.module 16 | #else 17 | let bundle = Bundle(for: Provider.self) 18 | #endif 19 | 20 | var path = bundle.path(forResource: locale, 21 | ofType: Config.pathExtension, 22 | inDirectory: Config.dirPath) ?? 23 | bundle.path(forResource: locale, 24 | ofType: Config.pathExtension, 25 | inDirectory: Config.dirFrameworkPath) 26 | 27 | if !Config.dirResourcePath.isEmpty { 28 | path = "\(Config.dirResourcePath)/\(locale).\(Config.pathExtension)" 29 | } 30 | 31 | if let resourcePath = Bundle(for: Provider.self).resourcePath { 32 | let bundlePath = resourcePath + "/Faker.bundle" 33 | 34 | if let bundle = Bundle(path: bundlePath) { 35 | path = bundle.path(forResource: locale, ofType: Config.pathExtension) 36 | } 37 | } 38 | 39 | if let path = path { 40 | let fileURL = URL(fileURLWithPath: path) 41 | 42 | if let data = try? Data(contentsOf: fileURL) { 43 | translation = data 44 | translations[locale] = data 45 | } 46 | } 47 | } 48 | 49 | return translation 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Extensions/ArrayExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Array { 4 | func at(_ index: Int?) -> Element? { 5 | guard let index = index, index >= 0 && index < endIndex else { 6 | return nil 7 | } 8 | 9 | return self[index] 10 | } 11 | 12 | func random() -> Element? { 13 | // swiftlint:disable empty_count 14 | guard count > 0 else { 15 | return nil 16 | } 17 | #if swift(>=4.2) 18 | return self.randomElement() 19 | #else 20 | return self[Int(arc4random_uniform(UInt32(count)))] 21 | #endif 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Extensions/StringExtensions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String { 4 | static func characters(amount: Int = 255) -> String { 5 | var chars = "" 6 | 7 | if amount > 0 { 8 | for _ in 0..=4.2) 10 | let char = Character(UnicodeScalar(Int.random(in: 0.. String { 15 | return generate("address.city") 16 | } 17 | 18 | public func streetName() -> String { 19 | return generate("address.street_name") 20 | } 21 | 22 | public func secondaryAddress() -> String { 23 | return numerify(generate("address.secondary_address")) 24 | } 25 | 26 | public func streetAddress(includeSecondary: Bool = false) -> String { 27 | var streetAddress = numerify(generate("address.street_address")) 28 | 29 | if includeSecondary { 30 | streetAddress += " " + secondaryAddress() 31 | } 32 | 33 | return streetAddress 34 | } 35 | 36 | public func buildingNumber() -> String { 37 | return bothify(generate("address.building_number")) 38 | } 39 | 40 | public func postcode(stateAbbreviation: String = "") -> String { 41 | if stateAbbreviation.isEmpty { 42 | return bothify(generate("address.postcode")) 43 | } 44 | 45 | return bothify(generate("address.postcode_by_state.\(stateAbbreviation)")) 46 | } 47 | 48 | public func timeZone() -> String { 49 | return generate("address.time_zone") 50 | } 51 | 52 | public func streetSuffix() -> String { 53 | return generate("address.street_suffix") 54 | } 55 | 56 | public func citySuffix() -> String { 57 | return generate("address.city_suffix") 58 | } 59 | 60 | public func cityPrefix() -> String { 61 | return generate("address.city_prefix") 62 | } 63 | 64 | public func stateAbbreviation() -> String { 65 | return generate("address.state_abbr") 66 | } 67 | 68 | public func state() -> String { 69 | return generate("address.state") 70 | } 71 | 72 | public func county() -> String { 73 | return generate("address.county") 74 | } 75 | 76 | public func country() -> String { 77 | return generate("address.country") 78 | } 79 | 80 | public func countryCode() -> String { 81 | return generate("address.country_code") 82 | } 83 | 84 | public func latitude() -> Double { 85 | return drand48() * 180.0 - 90.0 86 | } 87 | 88 | public func longitude() -> Double { 89 | return drand48() * 360.0 - 180.0 90 | } 91 | 92 | public func coordinate(inRadius radius: Double, fromCenter center: Location) -> Location { 93 | let y0 = center.latitude 94 | let x0 = center.longitude 95 | 96 | // Convert meters to degrees for radius 97 | let radiusInDegrees = radius / 111300.0 98 | 99 | // Random point in circle 100 | #if swift(>=4.2) 101 | let rhoRandom = Double.random(in: 0.. String { 4 | return generate("app.name") 5 | } 6 | 7 | public func version() -> String { 8 | return numerify(generate("app.version")) 9 | } 10 | 11 | public func author() -> String { 12 | return generate("app.author") 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Bank.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class Bank: Generator { 3 | public func name() -> String { 4 | return generate("bank.name") 5 | } 6 | 7 | public func swiftBic() -> String { 8 | return generate("bank.swiftBic") 9 | } 10 | 11 | public func iban() -> String { 12 | let bankCountryCode = generate("bank.ibanDetails.bankCountryCode") 13 | let bankCountryString = numerify("##") 14 | let ibanLetterCode = letterify(generate("bank.ibanDetails.ibanLetterCode")) 15 | let iban = numerify(generate("bank.ibanDetails.ibanDigits")) 16 | 17 | return bankCountryCode + bankCountryString + ibanLetterCode + iban 18 | } 19 | 20 | public func bban() -> String { 21 | let ibanLetterCode: String = letterify(generate("bank.ibanDetails.ibanLetterCode")) 22 | let iban: String = numerify(generate("bank.ibanDetails.ibanDigits")) 23 | 24 | return ibanLetterCode + iban 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Business.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Business: Generator { 5 | public func creditCardNumber() -> String { 6 | return generate("business.credit_card_numbers") 7 | } 8 | 9 | public func creditCardType() -> String { 10 | return generate("business.credit_card_types") 11 | } 12 | 13 | public func creditCardExpiryDate() -> Foundation.Date? { 14 | let dateString = generate("business.credit_card_expiry_dates") 15 | return dateFormatter.date(from: dateString) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Car.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Car: Generator { 5 | public func brand() -> String { 6 | return generate("car.brand") 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Cat.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Cat: Generator { 5 | public func name() -> String { 6 | return generate("cat.name") 7 | } 8 | 9 | public func breed() -> String { 10 | return generate("cat.breed") 11 | } 12 | 13 | public func registry() -> String { 14 | return generate("cat.registry") 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Commerce.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Commerce: Generator { 5 | public func color() -> String { 6 | return generate("commerce.color") 7 | } 8 | 9 | public func department(maximum: Int = 3, fixedAmount: Bool = false) -> String { 10 | #if swift(>=4.2) 11 | let amount = fixedAmount ? maximum : 1 + Int.random(in: 0.. 1 { 21 | department = merge(categories: fetchedCategories) 22 | } else if count == 1 { 23 | department = fetchedCategories[0] 24 | } 25 | 26 | return department 27 | } 28 | 29 | public func productName() -> String { 30 | return generate("commerce.product_name.adjective") + " " 31 | + generate("commerce.product_name.material") + " " 32 | + generate("commerce.product_name.product") 33 | } 34 | 35 | public func price() -> Double { 36 | let arc4randoMax: Double = 0x100000000 37 | #if swift(>=4.2) 38 | return floor(Double((Double(UInt32.random(in: 0.. [String] { 47 | var categories: [String] = [] 48 | 49 | while categories.count < amount { 50 | let category = generate("commerce.department") 51 | 52 | if !categories.contains(category) { 53 | categories.append(category) 54 | } 55 | } 56 | 57 | return categories 58 | } 59 | 60 | public func merge(categories: [String]) -> String { 61 | let separator = generate("separator") 62 | let commaSeparated = categories[0.. String { 6 | return generate("company.name") 7 | } 8 | 9 | public func suffix() -> String { 10 | return generate("company.suffix") 11 | } 12 | 13 | public func catchPhrase() -> String { 14 | return randomWordsFromKey("company.buzzwords") 15 | } 16 | 17 | public func bs() -> String { 18 | return randomWordsFromKey("company.bs") 19 | } 20 | 21 | public func logo() -> String { 22 | #if swift(>=4.2) 23 | let number = Int.random(in: 0..<13) + 1 24 | #else 25 | let number = Int(arc4random_uniform(13)) + 1 26 | #endif 27 | return "https://pigment.github.io/fake-logos/logos/medium/color/\(number).png" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Date.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Date: Generator { 5 | public func backward(days: Int) -> Foundation.Date { 6 | return todayAddingDays(-days) 7 | } 8 | 9 | public func forward(_ days: Int) -> Foundation.Date { 10 | return todayAddingDays(days) 11 | } 12 | 13 | public func between(_ from: Foundation.Date, _ to: Foundation.Date) -> Foundation.Date { 14 | let fromInSeconds = from.timeIntervalSince1970 15 | let toInSeconds = to.timeIntervalSince1970 16 | let targetInSeconds = Number().randomDouble(min: fromInSeconds, max: toInSeconds) 17 | return Foundation.Date(timeIntervalSince1970: targetInSeconds) 18 | } 19 | 20 | public func birthday(_ minAge: Int, _ maxAge: Int) -> Foundation.Date { 21 | let olderAgeBirthDate = todayAddingYears(-maxAge) 22 | let earlierAgeBirthDate = todayAddingYears(-minAge) 23 | return between(earlierAgeBirthDate, olderAgeBirthDate) 24 | } 25 | 26 | private func todayAddingDays(_ days: Int) -> Foundation.Date { 27 | var dateComponents = DateComponents() 28 | dateComponents.day = days 29 | return todayAdding(dateComponents) 30 | } 31 | 32 | private func todayAddingYears(_ years: Int) -> Foundation.Date { 33 | var dateComponents = DateComponents() 34 | dateComponents.year = years 35 | return todayAdding(dateComponents) 36 | } 37 | 38 | private func todayAdding(_ dateComponents: DateComponents) -> Foundation.Date { 39 | let calendar = Calendar.current 40 | 41 | let todayDate = Foundation.Date() 42 | return calendar.date(byAdding: dateComponents, to: todayDate)! 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Gender.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Gender: Generator { 5 | public func type() -> String { 6 | return generate("gender.type") 7 | } 8 | 9 | public func binaryType() -> String { 10 | return generate("gender.binary_type") 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Generator.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public class Generator { 5 | // swiftlint:disable nesting 6 | public struct Constants { 7 | public static let uppercaseLetters = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 8 | public static let letters = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") 9 | public static let numbers = Array("0123456789") 10 | } 11 | 12 | let parser: Parser 13 | let dateFormatter: DateFormatter 14 | 15 | public required init(parser: Parser = Parser()) { 16 | self.parser = parser 17 | dateFormatter = DateFormatter() 18 | dateFormatter.dateFormat = "yyyy-MM-dd" 19 | } 20 | 21 | public func generate(_ key: String) -> String { 22 | return parser.fetch(key) 23 | } 24 | 25 | // MARK: - Filling 26 | 27 | public func numerify(_ string: String) -> String { 28 | let count = UInt32(Constants.numbers.count) 29 | 30 | return String(string.enumerated().map { (index, item) in 31 | #if swift(>=4.2) 32 | let numberIndex = index == 0 ? UInt32.random(in: 0..<(count - 1)) : UInt32.random(in: 0.. String { 42 | return String(string.enumerated().map { _, item in 43 | #if swift(>=4.2) 44 | let char = Constants.uppercaseLetters.randomElement() ?? Character("") 45 | #else 46 | let count = UInt32(Constants.uppercaseLetters.count) 47 | let char = Constants.uppercaseLetters[Int(arc4random_uniform(count))] 48 | #endif 49 | return String(item) == "?" ? char : item 50 | }) 51 | } 52 | 53 | public func bothify(_ string: String) -> String { 54 | return letterify(numerify(string)) 55 | } 56 | 57 | public func alphaNumerify(_ string: String) -> String { 58 | return string.replacingOccurrences(of: "[^A-Za-z0-9_]", 59 | with: "", 60 | options: .regularExpression, 61 | range: nil) 62 | } 63 | 64 | public func randomWordsFromKey(_ key: String) -> String { 65 | var string = "" 66 | 67 | var list = [String]() 68 | if let wordsList = parser.fetchRaw(key) as? [[String]] { 69 | for words in wordsList { 70 | if let item = words.random() { 71 | list.append(item) 72 | } 73 | } 74 | 75 | string = list.joined(separator: " ") 76 | } 77 | 78 | return string 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Ham.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class Ham: Generator { 3 | public func name() -> String { 4 | return generate("ham.name") 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Hobbit.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Hobbit: Generator { 5 | public func character() -> String { 6 | return generate("hobbit.character") 7 | } 8 | 9 | public func thorinsCompany() -> String { 10 | return generate("hobbit.thorins_company") 11 | } 12 | 13 | public func quote() -> String { 14 | return generate("hobbit.quote") 15 | } 16 | 17 | public func location() -> String { 18 | return generate("hobbit.location") 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/House.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class House: Generator { 3 | public func furniture() -> String { 4 | return generate("house.furniture") 5 | } 6 | 7 | public func room() -> String { 8 | return generate("house.room") 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Internet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Internet: Generator { 5 | public required init(parser: Parser) { 6 | super.init(parser: parser) 7 | } 8 | 9 | public func username(separator: String? = nil) -> String { 10 | #if swift(>=4.2) 11 | let lastRandomComponent = Int.random(in: 0..<10000) 12 | #else 13 | let lastRandomComponent = arc4random_uniform(10000) 14 | #endif 15 | let components: [String] = [ 16 | generate("name.first_name"), 17 | generate("name.last_name"), 18 | "\(lastRandomComponent)" 19 | ] 20 | 21 | let randomCount = components.count - 1 22 | #if swift(>=4.2) 23 | let count = Int.random(in: 0.. String { 39 | return domainWord(alphaNumericOnly: alphaNumericOnly) + "." + domainSuffix() 40 | } 41 | 42 | public func domainWord(alphaNumericOnly: Bool = true) -> String { 43 | let nameParts = generate("company.name").components(separatedBy: " ") 44 | var name = "" 45 | 46 | if let first = nameParts.first { 47 | name = first 48 | } else { 49 | name = letterify("?????") 50 | } 51 | 52 | let result = alphaNumericOnly ? alphaNumerify(name) : name 53 | 54 | return result.lowercased() 55 | } 56 | 57 | public func domainSuffix() -> String { 58 | return generate("internet.domain_suffix") 59 | } 60 | 61 | public func email() -> String { 62 | return [username(), domainName()].joined(separator: "@") 63 | } 64 | 65 | public func freeEmail() -> String { 66 | return [username(), generate("internet.free_email")].joined(separator: "@") 67 | } 68 | 69 | public func safeEmail() -> String { 70 | let topLevelDomains = ["org", "com", "net"] 71 | #if swift(>=4.2) 72 | let topLevelDomain = topLevelDomains.randomElement() ?? "" 73 | #else 74 | let count = UInt32(topLevelDomains.count) 75 | let topLevelDomain = topLevelDomains[Int(arc4random_uniform(count))] 76 | #endif 77 | 78 | return [username(), "example." + topLevelDomain].joined(separator: "@") 79 | } 80 | 81 | public func password(minimumLength: Int = 8, maximumLength: Int = 16) -> String { 82 | var temp = String.characters(amount: minimumLength) 83 | let diffLength = maximumLength - minimumLength 84 | 85 | if diffLength > 0 { 86 | #if swift(>=4.2) 87 | let diffRandom = Int.random(in: 0.. String { 98 | #if swift(>=4.2) 99 | let randomNumber = UInt32.random(in: 0.. String { 111 | #if swift(>=4.2) 112 | let randomNumber = UInt32.random(in: 0.. String { 127 | return "https://\(domainName())/\(username())" 128 | } 129 | 130 | public func image(width: Int = 320, height: Int = 200) -> String { 131 | return "https://lorempixel.com/\(width)/\(height)" 132 | } 133 | 134 | public func templateImage(width: Int = 320, height: Int = 200, 135 | backColorHex: String = "000000", frontColorHex: String = "ffffff") -> String { 136 | return "https://dummyimage.com/\(width)x\(height)/\(backColorHex)/\(frontColorHex)" 137 | } 138 | 139 | public func hashtag() -> String { 140 | return generate("internet.hashtag") 141 | } 142 | 143 | // @ToDo - slug 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Lorem.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Faker { 4 | public final class Lorem: Generator { 5 | public func word() -> String { 6 | return generate("lorem.words") 7 | } 8 | 9 | public func words(amount: Int = 3) -> String { 10 | var words: [String] = [] 11 | 12 | for _ in 0.. String { 20 | return characters(amount: 1) 21 | } 22 | 23 | public func characters(amount: Int = 255) -> String { 24 | return String.characters(amount: amount) 25 | } 26 | 27 | public func sentence(wordsAmount: Int = 4) -> String { 28 | var sentence = words(amount: wordsAmount) + "." 29 | sentence.replaceSubrange(sentence.startIndex...sentence.startIndex, 30 | with: String(sentence[sentence.startIndex]).capitalized) 31 | return sentence 32 | } 33 | 34 | public func sentences(amount: Int = 3) -> String { 35 | var sentences: [String] = [] 36 | 37 | for _ in 0.. String { 45 | return sentences(amount: sentencesAmount) 46 | } 47 | 48 | public func paragraphs(amount: Int = 3) -> String { 49 | var paragraphs: [String] = [] 50 | 51 | for _ in 0.. String { 4 | return generate("name.name") 5 | } 6 | 7 | public func firstName() -> String { 8 | return generate("name.first_name") 9 | } 10 | 11 | public func lastName() -> String { 12 | return generate("name.last_name") 13 | } 14 | 15 | public func prefix() -> String { 16 | return generate("name.prefix") 17 | } 18 | 19 | public func suffix() -> String { 20 | return generate("name.suffix") 21 | } 22 | 23 | public func title() -> String { 24 | return generate("name.title.descriptor") + " " 25 | + generate("name.title.level") + " " 26 | + generate("name.title.job") 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Number.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | #if !os(Linux) 3 | import CoreGraphics 4 | #endif 5 | 6 | extension Faker { 7 | public final class Number: Generator { 8 | fileprivate var lastUsedId: Int64 = 0 9 | 10 | public func randomBool() -> Bool { 11 | return randomInt() % 2 == 0 12 | } 13 | 14 | public func randomInt(min: Int = 0, max: Int = 1000) -> Int { 15 | var rand: Int = 0 16 | #if swift(>=4.2) 17 | rand = Int.random(in: rand..= 0 && max - Int.max >= min { 24 | return min + rand 25 | } 26 | 27 | return min + (rand % (max - min)) 28 | } 29 | 30 | public func randomFloat(min: Float = 0, max: Float = 1000) -> Float { 31 | #if swift(>=4.2) 32 | return (Float.random(in: 0.. CGFloat { 40 | return CGFloat(Float(arc4random()) / Float(UInt32.max)) * (max - min) + min 41 | } 42 | #endif 43 | 44 | public func randomDouble(min: Double = 0, max: Double = 1000) -> Double { 45 | #if swift(>=4.2) 46 | return (Double.random(in: 0.. Int { 54 | #if os(Linux) 55 | // increasing just by one on linux due to the lack of an method like OSAtomicIncrement64 56 | lastUsedId += 1 57 | #else 58 | OSAtomicIncrement64(&lastUsedId) 59 | #endif 60 | return Int(lastUsedId) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/PhoneNumber.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class PhoneNumber: Generator { 3 | public func phoneNumber() -> String { 4 | return numerify(generate("phone_number.formats")) 5 | } 6 | 7 | public func cellPhone() -> String { 8 | return numerify(generate("cell_phone.formats")) 9 | } 10 | 11 | // US only 12 | public func areaCode() -> String { 13 | return generate("phone_number.area_code") 14 | } 15 | 16 | // US only 17 | public func exchangeCode() -> String { 18 | return generate("phone_number.exchange_code") 19 | } 20 | 21 | // US only 22 | public func subscriberNumber() -> String { 23 | return numerify("####") 24 | } 25 | 26 | public func numberExtension(_ length: Int) -> String { 27 | var template = "" 28 | 29 | for _ in 1...length { 30 | template += "#" 31 | } 32 | 33 | return numerify(template) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/ProgrammingLanguage.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class ProgrammingLanguage: Generator { 3 | public func name() -> String { 4 | return generate("programming_language.name") 5 | } 6 | 7 | public func creator() -> String { 8 | return generate("programming_language.creator") 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Team.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class Team: Generator { 3 | public func name() -> String { 4 | return generate("team.name") 5 | } 6 | 7 | public func creature() -> String { 8 | return generate("team.creature") 9 | } 10 | 11 | public func state() -> String { 12 | return generate("address.state").capitalized 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Vehicle.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class Vehicle: Generator { 3 | public func manufacture() -> String { 4 | return generate("vehicle.manufacture") 5 | } 6 | 7 | public func make() -> String { 8 | return generate("vehicle.makes") 9 | } 10 | 11 | public func colors() -> String { 12 | return generate("vehicle.colors") 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Generators/Zelda.swift: -------------------------------------------------------------------------------- 1 | extension Faker { 2 | public final class Zelda: Generator { 3 | public func game() -> String { 4 | return generate("zelda.game") 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Resources/Locales/de-CH.json: -------------------------------------------------------------------------------- 1 | { 2 | "de-CH": { 3 | "faker": { 4 | "address": { 5 | "country_code": [ 6 | "CH", 7 | "CH", 8 | "CH", 9 | "DE", 10 | "AT", 11 | "US", 12 | "LI", 13 | "US", 14 | "HK", 15 | "VN" 16 | ], 17 | "postcode": [ 18 | "1###", 19 | "2###", 20 | "3###", 21 | "4###", 22 | "5###", 23 | "6###", 24 | "7###", 25 | "8###", 26 | "9###" 27 | ], 28 | "default_country": [ 29 | "Schweiz" 30 | ] 31 | }, 32 | "company": { 33 | "suffix": [ 34 | "AG", 35 | "GmbH", 36 | "und Söhne", 37 | "und Partner", 38 | "& Co.", 39 | "Gruppe", 40 | "LLC", 41 | "Inc." 42 | ], 43 | "name": [ 44 | "#{Name.last_name} #{suffix}", 45 | "#{Name.last_name}-#{Name.last_name}", 46 | "#{Name.last_name}, #{Name.last_name} und #{Name.last_name}" 47 | ] 48 | }, 49 | "internet": { 50 | "domain_suffix": [ 51 | "com", 52 | "net", 53 | "biz", 54 | "ch", 55 | "de", 56 | "li", 57 | "at", 58 | "ch", 59 | "ch" 60 | ] 61 | }, 62 | "phone_number": { 63 | "formats": [ 64 | "0800 ### ###", 65 | "0800 ## ## ##", 66 | "0## ### ## ##", 67 | "0## ### ## ##", 68 | "+41 ## ### ## ##", 69 | "0900 ### ###", 70 | "076 ### ## ##", 71 | "+4178 ### ## ##", 72 | "0041 79 ### ## ##" 73 | ] 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Resources/Locales/en-CA.json: -------------------------------------------------------------------------------- 1 | { 2 | "en-CA": { 3 | "faker": { 4 | "address": { 5 | "postcode": "/[A-CEJ-NPR-TVXY][0-9][A-CEJ-NPR-TV-Z] ?[0-9][A-CEJ-NPR-TV-Z][0-9]/", 6 | "state": [ 7 | "Alberta", 8 | "British Columbia", 9 | "Manitoba", 10 | "New Brunswick", 11 | "Newfoundland and Labrador", 12 | "Nova Scotia", 13 | "Northwest Territories", 14 | "Nunavut", 15 | "Ontario", 16 | "Prince Edward Island", 17 | "Quebec", 18 | "Saskatchewan", 19 | "Yukon" 20 | ], 21 | "state_abbr": [ 22 | "AB", 23 | "BC", 24 | "MB", 25 | "NB", 26 | "NL", 27 | "NS", 28 | "NU", 29 | "NT", 30 | "ON", 31 | "PE", 32 | "QC", 33 | "SK", 34 | "YT" 35 | ], 36 | "default_country": [ 37 | "Canada" 38 | ] 39 | }, 40 | "internet": { 41 | "free_email": [ 42 | "gmail.com", 43 | "yahoo.ca", 44 | "hotmail.com" 45 | ], 46 | "domain_suffix": [ 47 | "ca", 48 | "com", 49 | "biz", 50 | "info", 51 | "name", 52 | "net", 53 | "org" 54 | ] 55 | }, 56 | "phone_number": { 57 | "formats": [ 58 | "###-###-####", 59 | "(###)###-####", 60 | "###.###.####", 61 | "1-###-###-####", 62 | "###-###-#### x###", 63 | "(###)###-#### x###", 64 | "1-###-###-#### x###", 65 | "###.###.#### x###", 66 | "###-###-#### x####", 67 | "(###)###-#### x####", 68 | "1-###-###-#### x####", 69 | "###.###.#### x####", 70 | "###-###-#### x#####", 71 | "(###)###-#### x#####", 72 | "1-###-###-#### x#####", 73 | "###.###.#### x#####" 74 | ] 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Resources/Locales/en-GB.json: -------------------------------------------------------------------------------- 1 | { 2 | "en-GB": { 3 | "faker": { 4 | "address": { 5 | "postcode": "/[A-PR-UWYZ][A-HK-Y]?[0-9][ABEHMNPRVWXY0-9]? [0-9][ABD-HJLN-UW-Z]{2}/", 6 | "county": [ 7 | "Avon", 8 | "Bedfordshire", 9 | "Berkshire", 10 | "Borders", 11 | "Buckinghamshire", 12 | "Cambridgeshire", 13 | "Central", 14 | "Cheshire", 15 | "Cleveland", 16 | "Clwyd", 17 | "Cornwall", 18 | "County Antrim", 19 | "County Armagh", 20 | "County Down", 21 | "County Fermanagh", 22 | "County Londonderry", 23 | "County Tyrone", 24 | "Cumbria", 25 | "Derbyshire", 26 | "Devon", 27 | "Dorset", 28 | "Dumfries and Galloway", 29 | "Durham", 30 | "Dyfed", 31 | "East Sussex", 32 | "Essex", 33 | "Fife", 34 | "Gloucestershire", 35 | "Grampian", 36 | "Greater Manchester", 37 | "Gwent", 38 | "Gwynedd County", 39 | "Hampshire", 40 | "Herefordshire", 41 | "Hertfordshire", 42 | "Highlands and Islands", 43 | "Humberside", 44 | "Isle of Wight", 45 | "Kent", 46 | "Lancashire", 47 | "Leicestershire", 48 | "Lincolnshire", 49 | "Lothian", 50 | "Merseyside", 51 | "Mid Glamorgan", 52 | "Norfolk", 53 | "North Yorkshire", 54 | "Northamptonshire", 55 | "Northumberland", 56 | "Nottinghamshire", 57 | "Oxfordshire", 58 | "Powys", 59 | "Rutland", 60 | "Shropshire", 61 | "Somerset", 62 | "South Glamorgan", 63 | "South Yorkshire", 64 | "Staffordshire", 65 | "Strathclyde", 66 | "Suffolk", 67 | "Surrey", 68 | "Tayside", 69 | "Tyne and Wear", 70 | "Warwickshire", 71 | "West Glamorgan", 72 | "West Midlands", 73 | "West Sussex", 74 | "West Yorkshire", 75 | "Wiltshire", 76 | "Worcestershire" 77 | ], 78 | "uk_country": [ 79 | "England", 80 | "Scotland", 81 | "Wales", 82 | "Northern Ireland" 83 | ], 84 | "default_country": [ 85 | "England", 86 | "Scotland", 87 | "Wales", 88 | "Northern Ireland" 89 | ] 90 | }, 91 | "internet": { 92 | "domain_suffix": [ 93 | "co.uk", 94 | "com", 95 | "biz", 96 | "info", 97 | "name" 98 | ] 99 | }, 100 | "phone_number": { 101 | "formats": [ 102 | "01#### #####", 103 | "01### ######", 104 | "01#1 ### ####", 105 | "011# ### ####", 106 | "02# #### ####", 107 | "03## ### ####", 108 | "055 #### ####", 109 | "056 #### ####", 110 | "0800 ### ####", 111 | "08## ### ####", 112 | "09## ### ####", 113 | "016977 ####", 114 | "01### #####", 115 | "0500 ######", 116 | "0800 ######" 117 | ] 118 | }, 119 | "cell_phone": { 120 | "formats": [ 121 | "074## ######", 122 | "075## ######", 123 | "076## ######", 124 | "077## ######", 125 | "078## ######", 126 | "079## ######" 127 | ] 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Resources/Locales/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "ja": { 3 | "faker": { 4 | "address": { 5 | "postcode": [ 6 | "###-####" 7 | ], 8 | "state": [ 9 | "北海道", 10 | "青森県", 11 | "岩手県", 12 | "宮城県", 13 | "秋田県", 14 | "山形県", 15 | "福島県", 16 | "茨城県", 17 | "栃木県", 18 | "群馬県", 19 | "埼玉県", 20 | "千葉県", 21 | "東京都", 22 | "神奈川県", 23 | "新潟県", 24 | "富山県", 25 | "石川県", 26 | "福井県", 27 | "山梨県", 28 | "長野県", 29 | "岐阜県", 30 | "静岡県", 31 | "愛知県", 32 | "三重県", 33 | "滋賀県", 34 | "京都府", 35 | "大阪府", 36 | "兵庫県", 37 | "奈良県", 38 | "和歌山県", 39 | "鳥取県", 40 | "島根県", 41 | "岡山県", 42 | "広島県", 43 | "山口県", 44 | "徳島県", 45 | "香川県", 46 | "愛媛県", 47 | "高知県", 48 | "福岡県", 49 | "佐賀県", 50 | "長崎県", 51 | "熊本県", 52 | "大分県", 53 | "宮崎県", 54 | "鹿児島県", 55 | "沖縄県" 56 | ], 57 | "state_abbr": [ 58 | "1", 59 | "2", 60 | "3", 61 | "4", 62 | "5", 63 | "6", 64 | "7", 65 | "8", 66 | "9", 67 | "10", 68 | "11", 69 | "12", 70 | "13", 71 | "14", 72 | "15", 73 | "16", 74 | "17", 75 | "18", 76 | "19", 77 | "20", 78 | "21", 79 | "22", 80 | "23", 81 | "24", 82 | "25", 83 | "26", 84 | "27", 85 | "28", 86 | "29", 87 | "30", 88 | "31", 89 | "32", 90 | "33", 91 | "34", 92 | "35", 93 | "36", 94 | "37", 95 | "38", 96 | "39", 97 | "40", 98 | "41", 99 | "42", 100 | "43", 101 | "44", 102 | "45", 103 | "46", 104 | "47" 105 | ], 106 | "city_prefix": [ 107 | "北", 108 | "東", 109 | "西", 110 | "南", 111 | "新", 112 | "湖", 113 | "港" 114 | ], 115 | "city_suffix": [ 116 | "市", 117 | "区", 118 | "町", 119 | "村" 120 | ], 121 | "city": [ 122 | "#{city_prefix}#{Name.first_name}#{city_suffix}", 123 | "#{Name.first_name}#{city_suffix}", 124 | "#{city_prefix}#{Name.last_name}#{city_suffix}", 125 | "#{Name.last_name}#{city_suffix}" 126 | ], 127 | "street_name": [ 128 | "#{Name.first_name}#{street_suffix}", 129 | "#{Name.last_name}#{street_suffix}" 130 | ] 131 | }, 132 | "phone_number": { 133 | "formats": [ 134 | "0####-#-####", 135 | "0###-##-####", 136 | "0##-###-####", 137 | "0#-####-####" 138 | ] 139 | }, 140 | "cell_phone": { 141 | "formats": [ 142 | "090-####-####", 143 | "080-####-####", 144 | "070-####-####" 145 | ] 146 | }, 147 | "name": { 148 | "last_name": [ 149 | "佐藤", 150 | "鈴木", 151 | "高橋", 152 | "田中", 153 | "渡辺", 154 | "伊藤", 155 | "山本", 156 | "中村", 157 | "小林", 158 | "加藤", 159 | "吉田", 160 | "山田", 161 | "佐々木", 162 | "山口", 163 | "斎藤", 164 | "松本", 165 | "井上", 166 | "木村", 167 | "林", 168 | "清水" 169 | ], 170 | "first_name": [ 171 | "大翔", 172 | "蓮", 173 | "颯太", 174 | "樹", 175 | "大和", 176 | "陽翔", 177 | "陸斗", 178 | "太一", 179 | "海翔", 180 | "蒼空", 181 | "翼", 182 | "陽菜", 183 | "結愛", 184 | "結衣", 185 | "杏", 186 | "莉子", 187 | "美羽", 188 | "結菜", 189 | "心愛", 190 | "愛菜", 191 | "美咲" 192 | ], 193 | "name": [ 194 | "#{last_name} #{first_name}" 195 | ] 196 | }, 197 | "gender": { 198 | "binary_type": [ 199 | "女性", 200 | "男性" 201 | ] 202 | } 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /Pods/Fakery/Sources/Fakery/Resources/Locales/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "nl": { 3 | "faker": { 4 | "address": { 5 | "postcode": "####??" 6 | }, 7 | "bank": { 8 | "name": [ 9 | "UBS CLEARING AND EXECUTION SERVICES LIMITED", 10 | "ABN AMRO CORPORATE FINANCE LIMITED", 11 | "ABN AMRO FUND MANAGERS LIMITED", 12 | "ABN AMRO HOARE GOVETT SECURITIES", 13 | "ABN AMRO HOARE GOVETT CORPORATE FINANCE LTD.", 14 | "ALKEN ASSET MANAGEMENT", 15 | "ABN AMRO HOARE GOVETT LIMITED", 16 | "AAC CAPITAL PARTNERS LIMITED", 17 | "ABBOTSTONE AGRICULTURAL PROPERTY UNIT TRUST", 18 | "ABN AMRO QUOTED INVESTMENTS (UK) LIMITED", 19 | "ABN AMRO MEZZANINE (UK) LIMITED", 20 | "ABBEY LIFE", 21 | "SANTANDER UK PLC", 22 | "OTKRITIE SECURITIES LIMITED", 23 | "ABC INTERNATIONAL BANK PLC", 24 | "ALLIED BANK PHILIPPINES (UK) PLC", 25 | "ABU DHABI ISLAMIC BANK", 26 | "ABG SUNDAL COLLIER LIMITED", 27 | "PGMS (GLASGOW) LIMITED", 28 | "ABINGWORTH MANAGEMENT LIMITED", 29 | "THE ROYAL BANK OF SCOTLAND PLC (FORMER RBS NV)" 30 | ], 31 | "swiftBic": [ 32 | "AACCGB21", 33 | "AACNGB21", 34 | "AAFMGB21", 35 | "AAHOGB21", 36 | "AAHVGB21", 37 | "AANLGB21", 38 | "AANLGB2L", 39 | "AAOGGB21", 40 | "AAPEGB21", 41 | "AAPUGB21", 42 | "AAQIGB21", 43 | "ABAZGB21", 44 | "ABBEGB21", 45 | "ABBYGB2L", 46 | "ABCCGB22", 47 | "ABCEGB2L", 48 | "ABCMGB21", 49 | "ABDIGB21", 50 | "ABECGB21", 51 | "ABFIGB21", 52 | "ABMNGB21", 53 | "ABNAGB21VOC" 54 | ], 55 | "ibanDetails": { 56 | "bankCountryCode": "NL", 57 | "ibanLetterCode": ["RABO", "BUNQ", "ABNA", "INGB"], 58 | "ibanDigits": "############", 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Pods/Kingfisher/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Wei Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Cache/Storage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Storage.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 2018/10/15. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | /// Constants for some time intervals 30 | struct TimeConstants { 31 | static let secondsInOneMinute = 60 32 | static let minutesInOneHour = 60 33 | static let hoursInOneDay = 24 34 | static let secondsInOneDay = 86_400 35 | } 36 | 37 | /// Represents the expiration strategy used in storage. 38 | /// 39 | /// - never: The item never expires. 40 | /// - seconds: The item expires after a time duration of given seconds from now. 41 | /// - days: The item expires after a time duration of given days from now. 42 | /// - date: The item expires after a given date. 43 | public enum StorageExpiration { 44 | /// The item never expires. 45 | case never 46 | /// The item expires after a time duration of given seconds from now. 47 | case seconds(TimeInterval) 48 | /// The item expires after a time duration of given days from now. 49 | case days(Int) 50 | /// The item expires after a given date. 51 | case date(Date) 52 | /// Indicates the item is already expired. Use this to skip cache. 53 | case expired 54 | 55 | func estimatedExpirationSince(_ date: Date) -> Date { 56 | switch self { 57 | case .never: return .distantFuture 58 | case .seconds(let seconds): 59 | return date.addingTimeInterval(seconds) 60 | case .days(let days): 61 | let duration: TimeInterval = TimeInterval(TimeConstants.secondsInOneDay) * TimeInterval(days) 62 | return date.addingTimeInterval(duration) 63 | case .date(let ref): 64 | return ref 65 | case .expired: 66 | return .distantPast 67 | } 68 | } 69 | 70 | var estimatedExpirationSinceNow: Date { 71 | return estimatedExpirationSince(Date()) 72 | } 73 | 74 | var isExpired: Bool { 75 | return timeInterval <= 0 76 | } 77 | 78 | var timeInterval: TimeInterval { 79 | switch self { 80 | case .never: return .infinity 81 | case .seconds(let seconds): return seconds 82 | case .days(let days): return TimeInterval(TimeConstants.secondsInOneDay) * TimeInterval(days) 83 | case .date(let ref): return ref.timeIntervalSinceNow 84 | case .expired: return -(.infinity) 85 | } 86 | } 87 | } 88 | 89 | /// Represents the expiration extending strategy used in storage to after access. 90 | /// 91 | /// - none: The item expires after the original time, without extending after access. 92 | /// - cacheTime: The item expiration extends by the original cache time after each access. 93 | /// - expirationTime: The item expiration extends by the provided time after each access. 94 | public enum ExpirationExtending { 95 | /// The item expires after the original time, without extending after access. 96 | case none 97 | /// The item expiration extends by the original cache time after each access. 98 | case cacheTime 99 | /// The item expiration extends by the provided time after each access. 100 | case expirationTime(_ expiration: StorageExpiration) 101 | } 102 | 103 | /// Represents types which cost in memory can be calculated. 104 | public protocol CacheCostCalculable { 105 | var cacheCost: Int { get } 106 | } 107 | 108 | /// Represents types which can be converted to and from data. 109 | public protocol DataTransformable { 110 | func toData() throws -> Data 111 | static func fromData(_ data: Data) throws -> Self 112 | static var empty: Self { get } 113 | } 114 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/General/ImageSource/Resource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Resource.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 15/4/6. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | /// Represents an image resource at a certain url and a given cache key. 30 | /// Kingfisher will use a `Resource` to download a resource from network and cache it with the cache key when 31 | /// using `Source.network` as its image setting source. 32 | public protocol Resource { 33 | 34 | /// The key used in cache. 35 | var cacheKey: String { get } 36 | 37 | /// The target image URL. 38 | var downloadURL: URL { get } 39 | } 40 | 41 | extension Resource { 42 | 43 | /// Converts `self` to a valid `Source` based on its `downloadURL` scheme. A `.provider` with 44 | /// `LocalFileImageDataProvider` associated will be returned if the URL points to a local file. Otherwise, 45 | /// `.network` is returned. 46 | public func convertToSource() -> Source { 47 | return downloadURL.isFileURL ? 48 | .provider(LocalFileImageDataProvider(fileURL: downloadURL, cacheKey: cacheKey)) : 49 | .network(self) 50 | } 51 | } 52 | 53 | /// ImageResource is a simple combination of `downloadURL` and `cacheKey`. 54 | /// When passed to image view set methods, Kingfisher will try to download the target 55 | /// image from the `downloadURL`, and then store it with the `cacheKey` as the key in cache. 56 | public struct ImageResource: Resource { 57 | 58 | // MARK: - Initializers 59 | 60 | /// Creates an image resource. 61 | /// 62 | /// - Parameters: 63 | /// - downloadURL: The target image URL from where the image can be downloaded. 64 | /// - cacheKey: The cache key. If `nil`, Kingfisher will use the `absoluteString` of `downloadURL` as the key. 65 | /// Default is `nil`. 66 | public init(downloadURL: URL, cacheKey: String? = nil) { 67 | self.downloadURL = downloadURL 68 | self.cacheKey = cacheKey ?? downloadURL.absoluteString 69 | } 70 | 71 | // MARK: Protocol Conforming 72 | 73 | /// The key used in cache. 74 | public let cacheKey: String 75 | 76 | /// The target image URL. 77 | public let downloadURL: URL 78 | } 79 | 80 | /// URL conforms to `Resource` in Kingfisher. 81 | /// The `absoluteString` of this URL is used as `cacheKey`. And the URL itself will be used as `downloadURL`. 82 | /// If you need customize the url and/or cache key, use `ImageResource` instead. 83 | extension URL: Resource { 84 | public var cacheKey: String { return absoluteString } 85 | public var downloadURL: URL { return self } 86 | } 87 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/General/ImageSource/Source.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Source.swift 3 | // Kingfisher 4 | // 5 | // Created by onevcat on 2018/11/17. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | /// Represents an image setting source for Kingfisher methods. 30 | /// 31 | /// A `Source` value indicates the way how the target image can be retrieved and cached. 32 | /// 33 | /// - network: The target image should be got from network remotely. The associated `Resource` 34 | /// value defines detail information like image URL and cache key. 35 | /// - provider: The target image should be provided in a data format. Normally, it can be an image 36 | /// from local storage or in any other encoding format (like Base64). 37 | public enum Source { 38 | 39 | /// Represents the source task identifier when setting an image to a view with extension methods. 40 | public enum Identifier { 41 | 42 | /// The underlying value type of source identifier. 43 | public typealias Value = UInt 44 | static var current: Value = 0 45 | static func next() -> Value { 46 | current += 1 47 | return current 48 | } 49 | } 50 | 51 | // MARK: Member Cases 52 | 53 | /// The target image should be got from network remotely. The associated `Resource` 54 | /// value defines detail information like image URL and cache key. 55 | case network(Resource) 56 | 57 | /// The target image should be provided in a data format. Normally, it can be an image 58 | /// from local storage or in any other encoding format (like Base64). 59 | case provider(ImageDataProvider) 60 | 61 | // MARK: Getting Properties 62 | 63 | /// The cache key defined for this source value. 64 | public var cacheKey: String { 65 | switch self { 66 | case .network(let resource): return resource.cacheKey 67 | case .provider(let provider): return provider.cacheKey 68 | } 69 | } 70 | 71 | /// The URL defined for this source value. 72 | /// 73 | /// For a `.network` source, it is the `downloadURL` of associated `Resource` instance. 74 | /// For a `.provider` value, it is always `nil`. 75 | public var url: URL? { 76 | switch self { 77 | case .network(let resource): return resource.downloadURL 78 | case .provider(let provider): return provider.contentURL 79 | } 80 | } 81 | } 82 | 83 | extension Source { 84 | var asResource: Resource? { 85 | guard case .network(let resource) = self else { 86 | return nil 87 | } 88 | return resource 89 | } 90 | 91 | var asProvider: ImageDataProvider? { 92 | guard case .provider(let provider) = self else { 93 | return nil 94 | } 95 | return provider 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/General/Kingfisher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Kingfisher.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 16/9/14. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | import ImageIO 29 | 30 | #if os(macOS) 31 | import AppKit 32 | public typealias KFCrossPlatformImage = NSImage 33 | public typealias KFCrossPlatformView = NSView 34 | public typealias KFCrossPlatformColor = NSColor 35 | public typealias KFCrossPlatformImageView = NSImageView 36 | public typealias KFCrossPlatformButton = NSButton 37 | #else 38 | import UIKit 39 | public typealias KFCrossPlatformImage = UIImage 40 | public typealias KFCrossPlatformColor = UIColor 41 | #if !os(watchOS) 42 | public typealias KFCrossPlatformImageView = UIImageView 43 | public typealias KFCrossPlatformView = UIView 44 | public typealias KFCrossPlatformButton = UIButton 45 | #if canImport(TVUIKit) 46 | import TVUIKit 47 | #endif 48 | #else 49 | import WatchKit 50 | #endif 51 | #endif 52 | 53 | /// Wrapper for Kingfisher compatible types. This type provides an extension point for 54 | /// connivence methods in Kingfisher. 55 | public struct KingfisherWrapper { 56 | public let base: Base 57 | public init(_ base: Base) { 58 | self.base = base 59 | } 60 | } 61 | 62 | /// Represents an object type that is compatible with Kingfisher. You can use `kf` property to get a 63 | /// value in the namespace of Kingfisher. 64 | public protocol KingfisherCompatible: AnyObject { } 65 | 66 | /// Represents a value type that is compatible with Kingfisher. You can use `kf` property to get a 67 | /// value in the namespace of Kingfisher. 68 | public protocol KingfisherCompatibleValue {} 69 | 70 | extension KingfisherCompatible { 71 | /// Gets a namespace holder for Kingfisher compatible types. 72 | public var kf: KingfisherWrapper { 73 | get { return KingfisherWrapper(self) } 74 | set { } 75 | } 76 | } 77 | 78 | extension KingfisherCompatibleValue { 79 | /// Gets a namespace holder for Kingfisher compatible types. 80 | public var kf: KingfisherWrapper { 81 | get { return KingfisherWrapper(self) } 82 | set { } 83 | } 84 | } 85 | 86 | extension KFCrossPlatformImage: KingfisherCompatible { } 87 | #if !os(watchOS) 88 | extension KFCrossPlatformImageView: KingfisherCompatible { } 89 | extension KFCrossPlatformButton: KingfisherCompatible { } 90 | extension NSTextAttachment: KingfisherCompatible { } 91 | #else 92 | extension WKInterfaceImage: KingfisherCompatible { } 93 | #endif 94 | 95 | #if os(tvOS) && canImport(TVUIKit) 96 | @available(tvOS 12.0, *) 97 | extension TVMonogramView: KingfisherCompatible { } 98 | #endif 99 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Image/Placeholder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Placeholder.swift 3 | // Kingfisher 4 | // 5 | // Created by Tieme van Veen on 28/08/2017. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #if !os(watchOS) 28 | 29 | #if canImport(AppKit) && !targetEnvironment(macCatalyst) 30 | import AppKit 31 | #endif 32 | 33 | #if canImport(UIKit) 34 | import UIKit 35 | #endif 36 | 37 | /// Represents a placeholder type which could be set while loading as well as 38 | /// loading finished without getting an image. 39 | public protocol Placeholder { 40 | 41 | /// How the placeholder should be added to a given image view. 42 | func add(to imageView: KFCrossPlatformImageView) 43 | 44 | /// How the placeholder should be removed from a given image view. 45 | func remove(from imageView: KFCrossPlatformImageView) 46 | } 47 | 48 | /// Default implementation of an image placeholder. The image will be set or 49 | /// reset directly for `image` property of the image view. 50 | extension KFCrossPlatformImage: Placeholder { 51 | /// How the placeholder should be added to a given image view. 52 | public func add(to imageView: KFCrossPlatformImageView) { imageView.image = self } 53 | 54 | /// How the placeholder should be removed from a given image view. 55 | public func remove(from imageView: KFCrossPlatformImageView) { imageView.image = nil } 56 | } 57 | 58 | /// Default implementation of an arbitrary view as placeholder. The view will be 59 | /// added as a subview when adding and be removed from its super view when removing. 60 | /// 61 | /// To use your customize View type as placeholder, simply let it conforming to 62 | /// `Placeholder` by `extension MyView: Placeholder {}`. 63 | extension Placeholder where Self: KFCrossPlatformView { 64 | 65 | /// How the placeholder should be added to a given image view. 66 | public func add(to imageView: KFCrossPlatformImageView) { 67 | imageView.addSubview(self) 68 | translatesAutoresizingMaskIntoConstraints = false 69 | 70 | centerXAnchor.constraint(equalTo: imageView.centerXAnchor).isActive = true 71 | centerYAnchor.constraint(equalTo: imageView.centerYAnchor).isActive = true 72 | heightAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true 73 | widthAnchor.constraint(equalTo: imageView.widthAnchor).isActive = true 74 | } 75 | 76 | /// How the placeholder should be removed from a given image view. 77 | public func remove(from imageView: KFCrossPlatformImageView) { 78 | removeFromSuperview() 79 | } 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Kingfisher.h: -------------------------------------------------------------------------------- 1 | // 2 | // Kingfisher.h 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 15/4/6. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | 29 | //! Project version number for Kingfisher. 30 | FOUNDATION_EXPORT double KingfisherVersionNumber; 31 | 32 | //! Project version string for Kingfisher. 33 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[]; 34 | 35 | // In this header, you should import all the public headers of your framework using statements like #import 36 | 37 | 38 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Networking/AuthenticationChallengeResponsable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AuthenticationChallengeResponsable.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 2018/10/11. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | /// Protocol indicates that an authentication challenge could be handled. 30 | public protocol AuthenticationChallengeResponsable: AnyObject { 31 | 32 | /// Called when a session level authentication challenge is received. 33 | /// This method provide a chance to handle and response to the authentication 34 | /// challenge before downloading could start. 35 | /// 36 | /// - Parameters: 37 | /// - downloader: The downloader which receives this challenge. 38 | /// - challenge: An object that contains the request for authentication. 39 | /// - completionHandler: A handler that your delegate method must call. 40 | /// 41 | /// - Note: This method is a forward from `URLSessionDelegate.urlSession(:didReceiveChallenge:completionHandler:)`. 42 | /// Please refer to the document of it in `URLSessionDelegate`. 43 | func downloader( 44 | _ downloader: ImageDownloader, 45 | didReceive challenge: URLAuthenticationChallenge, 46 | completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 47 | 48 | /// Called when a task level authentication challenge is received. 49 | /// This method provide a chance to handle and response to the authentication 50 | /// challenge before downloading could start. 51 | /// 52 | /// - Parameters: 53 | /// - downloader: The downloader which receives this challenge. 54 | /// - task: The task whose request requires authentication. 55 | /// - challenge: An object that contains the request for authentication. 56 | /// - completionHandler: A handler that your delegate method must call. 57 | func downloader( 58 | _ downloader: ImageDownloader, 59 | task: URLSessionTask, 60 | didReceive challenge: URLAuthenticationChallenge, 61 | completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 62 | } 63 | 64 | extension AuthenticationChallengeResponsable { 65 | 66 | public func downloader( 67 | _ downloader: ImageDownloader, 68 | didReceive challenge: URLAuthenticationChallenge, 69 | completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 70 | { 71 | if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { 72 | if let trustedHosts = downloader.trustedHosts, trustedHosts.contains(challenge.protectionSpace.host) { 73 | let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!) 74 | completionHandler(.useCredential, credential) 75 | return 76 | } 77 | } 78 | 79 | completionHandler(.performDefaultHandling, nil) 80 | } 81 | 82 | public func downloader( 83 | _ downloader: ImageDownloader, 84 | task: URLSessionTask, 85 | didReceive challenge: URLAuthenticationChallenge, 86 | completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 87 | { 88 | completionHandler(.performDefaultHandling, nil) 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Networking/ImageDataProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageDataProcessor.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 2018/10/11. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | private let sharedProcessingQueue: CallbackQueue = 30 | .dispatch(DispatchQueue(label: "com.onevcat.Kingfisher.ImageDownloader.Process")) 31 | 32 | // Handles image processing work on an own process queue. 33 | class ImageDataProcessor { 34 | let data: Data 35 | let callbacks: [SessionDataTask.TaskCallback] 36 | let queue: CallbackQueue 37 | 38 | // Note: We have an optimization choice there, to reduce queue dispatch by checking callback 39 | // queue settings in each option... 40 | let onImageProcessed = Delegate<(Result, SessionDataTask.TaskCallback), Void>() 41 | 42 | init(data: Data, callbacks: [SessionDataTask.TaskCallback], processingQueue: CallbackQueue?) { 43 | self.data = data 44 | self.callbacks = callbacks 45 | self.queue = processingQueue ?? sharedProcessingQueue 46 | } 47 | 48 | func process() { 49 | queue.execute(doProcess) 50 | } 51 | 52 | private func doProcess() { 53 | var processedImages = [String: KFCrossPlatformImage]() 54 | for callback in callbacks { 55 | let processor = callback.options.processor 56 | var image = processedImages[processor.identifier] 57 | if image == nil { 58 | image = processor.process(item: .data(data), options: callback.options) 59 | processedImages[processor.identifier] = image 60 | } 61 | 62 | let result: Result 63 | if let image = image { 64 | var finalImage = image 65 | if let imageModifier = callback.options.imageModifier { 66 | finalImage = imageModifier.modify(image) 67 | } 68 | if callback.options.backgroundDecode { 69 | finalImage = finalImage.kf.decoded 70 | } 71 | result = .success(finalImage) 72 | } else { 73 | let error = KingfisherError.processorError( 74 | reason: .processingFailed(processor: processor, item: .data(data))) 75 | result = .failure(error) 76 | } 77 | onImageProcessed.call((result, callback)) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Networking/RedirectHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RedirectHandler.swift 3 | // Kingfisher 4 | // 5 | // Created by Roman Maidanovych on 2018/12/10. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | /// Represents and wraps a method for modifying request during an image download request redirection. 30 | public protocol ImageDownloadRedirectHandler { 31 | 32 | /// The `ImageDownloadRedirectHandler` contained will be used to change the request before redirection. 33 | /// This is the posibility you can modify the image download request during redirection. You can modify the 34 | /// request for some customizing purpose, such as adding auth token to the header, do basic HTTP auth or 35 | /// something like url mapping. 36 | /// 37 | /// Usually, you pass an `ImageDownloadRedirectHandler` as the associated value of 38 | /// `KingfisherOptionsInfoItem.redirectHandler` and use it as the `options` parameter in related methods. 39 | /// 40 | /// If you do nothing with the input `request` and return it as is, a downloading process will redirect with it. 41 | /// 42 | /// - Parameters: 43 | /// - task: The current `SessionDataTask` which triggers this redirect. 44 | /// - response: The response received during redirection. 45 | /// - newRequest: The request for redirection which can be modified. 46 | /// - completionHandler: A closure for being called with modified request. 47 | func handleHTTPRedirection( 48 | for task: SessionDataTask, 49 | response: HTTPURLResponse, 50 | newRequest: URLRequest, 51 | completionHandler: @escaping (URLRequest?) -> Void) 52 | } 53 | 54 | /// A wrapper for creating an `ImageDownloadRedirectHandler` easier. 55 | /// This type conforms to `ImageDownloadRedirectHandler` and wraps a redirect request modify block. 56 | public struct AnyRedirectHandler: ImageDownloadRedirectHandler { 57 | 58 | let block: (SessionDataTask, HTTPURLResponse, URLRequest, @escaping (URLRequest?) -> Void) -> Void 59 | 60 | public func handleHTTPRedirection( 61 | for task: SessionDataTask, 62 | response: HTTPURLResponse, 63 | newRequest: URLRequest, 64 | completionHandler: @escaping (URLRequest?) -> Void) 65 | { 66 | block(task, response, newRequest, completionHandler) 67 | } 68 | 69 | /// Creates a value of `ImageDownloadRedirectHandler` which runs `modify` block. 70 | /// 71 | /// - Parameter modify: The request modifying block runs when a request modifying task comes. 72 | /// 73 | public init(handle: @escaping (SessionDataTask, HTTPURLResponse, URLRequest, @escaping (URLRequest?) -> Void) -> Void) { 74 | block = handle 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Utility/Box.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Box.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 2018/3/17. 6 | // Copyright (c) 2019 Wei Wang 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | 28 | class Box { 29 | var value: T 30 | 31 | init(_ value: T) { 32 | self.value = value 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Utility/CallbackQueue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CallbackQueue.swift 3 | // Kingfisher 4 | // 5 | // Created by onevcat on 2018/10/15. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | /// Represents callback queue behaviors when an calling of closure be dispatched. 30 | /// 31 | /// - asyncMain: Dispatch the calling to `DispatchQueue.main` with an `async` behavior. 32 | /// - currentMainOrAsync: Dispatch the calling to `DispatchQueue.main` with an `async` behavior if current queue is not 33 | /// `.main`. Otherwise, call the closure immediately in current main queue. 34 | /// - untouch: Do not change the calling queue for closure. 35 | /// - dispatch: Dispatches to a specified `DispatchQueue`. 36 | public enum CallbackQueue { 37 | /// Dispatch the calling to `DispatchQueue.main` with an `async` behavior. 38 | case mainAsync 39 | /// Dispatch the calling to `DispatchQueue.main` with an `async` behavior if current queue is not 40 | /// `.main`. Otherwise, call the closure immediately in current main queue. 41 | case mainCurrentOrAsync 42 | /// Do not change the calling queue for closure. 43 | case untouch 44 | /// Dispatches to a specified `DispatchQueue`. 45 | case dispatch(DispatchQueue) 46 | 47 | public func execute(_ block: @escaping () -> Void) { 48 | switch self { 49 | case .mainAsync: 50 | DispatchQueue.main.async { block() } 51 | case .mainCurrentOrAsync: 52 | DispatchQueue.main.safeAsync { block() } 53 | case .untouch: 54 | block() 55 | case .dispatch(let queue): 56 | queue.async { block() } 57 | } 58 | } 59 | 60 | var queue: DispatchQueue { 61 | switch self { 62 | case .mainAsync: return .main 63 | case .mainCurrentOrAsync: return .main 64 | case .untouch: return OperationQueue.current?.underlyingQueue ?? .main 65 | case .dispatch(let queue): return queue 66 | } 67 | } 68 | } 69 | 70 | extension DispatchQueue { 71 | // This method will dispatch the `block` to self. 72 | // If `self` is the main queue, and current thread is main thread, the block 73 | // will be invoked immediately instead of being dispatched. 74 | func safeAsync(_ block: @escaping ()->()) { 75 | if self === DispatchQueue.main && Thread.isMainThread { 76 | block() 77 | } else { 78 | async { block() } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Utility/Delegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Delegate.swift 3 | // Kingfisher 4 | // 5 | // Created by onevcat on 2018/10/10. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | /// A class that keeps a weakly reference for `self` when implementing `onXXX` behaviors. 29 | /// Instead of remembering to keep `self` as weak in a stored closure: 30 | /// 31 | /// ```swift 32 | /// // MyClass.swift 33 | /// var onDone: (() -> Void)? 34 | /// func done() { 35 | /// onDone?() 36 | /// } 37 | /// 38 | /// // ViewController.swift 39 | /// var obj: MyClass? 40 | /// 41 | /// func doSomething() { 42 | /// obj = MyClass() 43 | /// obj!.onDone = { [weak self] in 44 | /// self?.reportDone() 45 | /// } 46 | /// } 47 | /// ``` 48 | /// 49 | /// You can create a `Delegate` and observe on `self`. Now, there is no retain cycle inside: 50 | /// 51 | /// ```swift 52 | /// // MyClass.swift 53 | /// let onDone = Delegate<(), Void>() 54 | /// func done() { 55 | /// onDone.call() 56 | /// } 57 | /// 58 | /// // ViewController.swift 59 | /// var obj: MyClass? 60 | /// 61 | /// func doSomething() { 62 | /// obj = MyClass() 63 | /// obj!.onDone.delegate(on: self) { (self, _) 64 | /// // `self` here is shadowed and does not keep a strong ref. 65 | /// // So you can release both `MyClass` instance and `ViewController` instance. 66 | /// self.reportDone() 67 | /// } 68 | /// } 69 | /// ``` 70 | /// 71 | public class Delegate { 72 | public init() {} 73 | 74 | private var block: ((Input) -> Output?)? 75 | public func delegate(on target: T, block: ((T, Input) -> Output)?) { 76 | self.block = { [weak target] input in 77 | guard let target = target else { return nil } 78 | return block?(target, input) 79 | } 80 | } 81 | 82 | public func call(_ input: Input) -> Output? { 83 | return block?(input) 84 | } 85 | 86 | public func callAsFunction(_ input: Input) -> Output? { 87 | return call(input) 88 | } 89 | } 90 | 91 | extension Delegate where Input == Void { 92 | public func call() -> Output? { 93 | return call(()) 94 | } 95 | 96 | public func callAsFunction() -> Output? { 97 | return call() 98 | } 99 | } 100 | 101 | extension Delegate where Input == Void, Output: OptionalProtocol { 102 | public func call() -> Output { 103 | return call(()) 104 | } 105 | 106 | public func callAsFunction() -> Output { 107 | return call() 108 | } 109 | } 110 | 111 | extension Delegate where Output: OptionalProtocol { 112 | public func call(_ input: Input) -> Output { 113 | if let result = block?(input) { 114 | return result 115 | } else { 116 | return Output._createNil 117 | } 118 | } 119 | 120 | public func callAsFunction(_ input: Input) -> Output { 121 | return call(input) 122 | } 123 | } 124 | 125 | public protocol OptionalProtocol { 126 | static var _createNil: Self { get } 127 | } 128 | extension Optional : OptionalProtocol { 129 | public static var _createNil: Optional { 130 | return nil 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Utility/Runtime.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Runtime.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 2018/10/12. 6 | // 7 | // Copyright (c) 2019 Wei Wang 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | func getAssociatedObject(_ object: Any, _ key: UnsafeRawPointer) -> T? { 30 | return objc_getAssociatedObject(object, key) as? T 31 | } 32 | 33 | func setRetainedAssociatedObject(_ object: Any, _ key: UnsafeRawPointer, _ value: T) { 34 | objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 35 | } 36 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Fakery (5.1.0) 3 | - Kingfisher (6.0.1) 4 | 5 | DEPENDENCIES: 6 | - Fakery 7 | - Kingfisher (~> 6.0) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - Fakery 12 | - Kingfisher 13 | 14 | SPEC CHECKSUMS: 15 | Fakery: a90caff00ca5cacde6c161c3eafc72314a03d34d 16 | Kingfisher: adde87a4f74f6a3845395769354efff593581740 17 | 18 | PODFILE CHECKSUM: 2e75b4b78d18cf325281d383317394c9eb3d64ac 19 | 20 | COCOAPODS: 1.10.0 21 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/Fakery-Faker.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/Fakery.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/Kingfisher.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/Pods-DynamicCell-DynamicCellUITests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/Pods-DynamicCell.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/Pods-DynamicCellTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/mohannad.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Fakery-Faker.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 1 13 | 14 | Fakery.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 0 20 | 21 | Kingfisher.xcscheme 22 | 23 | isShown 24 | 25 | orderHint 26 | 2 27 | 28 | Pods-DynamicCell-DynamicCellUITests.xcscheme 29 | 30 | isShown 31 | 32 | orderHint 33 | 4 34 | 35 | Pods-DynamicCell.xcscheme 36 | 37 | isShown 38 | 39 | orderHint 40 | 3 41 | 42 | Pods-DynamicCellTests.xcscheme 43 | 44 | isShown 45 | 46 | orderHint 47 | 5 48 | 49 | 50 | SuppressBuildableAutocreation 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/Fakery-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 5.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/Fakery-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Fakery : NSObject 3 | @end 4 | @implementation PodsDummy_Fakery 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/Fakery-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/Fakery-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double FakeryVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char FakeryVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/Fakery.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Fakery 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Fakery 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/Fakery.modulemap: -------------------------------------------------------------------------------- 1 | framework module Fakery { 2 | umbrella header "Fakery-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/Fakery.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Fakery 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Fakery 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Fakery/ResourceBundle-Faker-Fakery-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleIdentifier 8 | ${PRODUCT_BUNDLE_IDENTIFIER} 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundleName 12 | ${PRODUCT_NAME} 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 5.1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 6.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Kingfisher : NSObject 3 | @end 4 | @implementation PodsDummy_Kingfisher 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "Kingfisher.h" 14 | 15 | FOUNDATION_EXPORT double KingfisherVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[]; 17 | 18 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kingfisher 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher.modulemap: -------------------------------------------------------------------------------- 1 | framework module Kingfisher { 2 | umbrella header "Kingfisher-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kingfisher 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Fakery 5 | 6 | Licensed under the **MIT** license 7 | 8 | > Copyright (c) 2015 Vadym Markov 9 | > 10 | > Permission is hereby granted, free of charge, to any person obtaining 11 | > a copy of this software and associated documentation files (the 12 | > "Software"), to deal in the Software without restriction, including 13 | > without limitation the rights to use, copy, modify, merge, publish, 14 | > distribute, sublicense, and/or sell copies of the Software, and to 15 | > permit persons to whom the Software is furnished to do so, subject to 16 | > the following conditions: 17 | > 18 | > The above copyright notice and this permission notice shall be 19 | > included in all copies or substantial portions of the Software. 20 | > 21 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | 29 | 30 | ## Kingfisher 31 | 32 | The MIT License (MIT) 33 | 34 | Copyright (c) 2019 Wei Wang 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | copies of the Software, and to permit persons to whom the Software is 41 | furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all 44 | copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | SOFTWARE. 53 | 54 | 55 | Generated by CocoaPods - https://cocoapods.org 56 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Licensed under the **MIT** license 18 | 19 | > Copyright (c) 2015 Vadym Markov 20 | > 21 | > Permission is hereby granted, free of charge, to any person obtaining 22 | > a copy of this software and associated documentation files (the 23 | > "Software"), to deal in the Software without restriction, including 24 | > without limitation the rights to use, copy, modify, merge, publish, 25 | > distribute, sublicense, and/or sell copies of the Software, and to 26 | > permit persons to whom the Software is furnished to do so, subject to 27 | > the following conditions: 28 | > 29 | > The above copyright notice and this permission notice shall be 30 | > included in all copies or substantial portions of the Software. 31 | > 32 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 33 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 34 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 35 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 36 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 37 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 38 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 39 | 40 | License 41 | MIT 42 | Title 43 | Fakery 44 | Type 45 | PSGroupSpecifier 46 | 47 | 48 | FooterText 49 | The MIT License (MIT) 50 | 51 | Copyright (c) 2019 Wei Wang 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a copy 54 | of this software and associated documentation files (the "Software"), to deal 55 | in the Software without restriction, including without limitation the rights 56 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 57 | copies of the Software, and to permit persons to whom the Software is 58 | furnished to do so, subject to the following conditions: 59 | 60 | The above copyright notice and this permission notice shall be included in all 61 | copies or substantial portions of the Software. 62 | 63 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 66 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 67 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 68 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 69 | SOFTWARE. 70 | 71 | 72 | License 73 | MIT 74 | Title 75 | Kingfisher 76 | Type 77 | PSGroupSpecifier 78 | 79 | 80 | FooterText 81 | Generated by CocoaPods - https://cocoapods.org 82 | Title 83 | 84 | Type 85 | PSGroupSpecifier 86 | 87 | 88 | StringsTable 89 | Acknowledgements 90 | Title 91 | Acknowledgements 92 | 93 | 94 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_DynamicCell_DynamicCellUITests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_DynamicCell_DynamicCellUITests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Fakery/Fakery.framework 3 | ${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Fakery.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Fakery/Fakery.framework 3 | ${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Fakery.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_DynamicCell_DynamicCellUITestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_DynamicCell_DynamicCellUITestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery/Fakery.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" -framework "Fakery" -framework "Foundation" -framework "Kingfisher" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_DynamicCell_DynamicCellUITests { 2 | umbrella header "Pods-DynamicCell-DynamicCellUITests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell-DynamicCellUITests/Pods-DynamicCell-DynamicCellUITests.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery/Fakery.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" -framework "Fakery" -framework "Foundation" -framework "Kingfisher" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Fakery 5 | 6 | Licensed under the **MIT** license 7 | 8 | > Copyright (c) 2015 Vadym Markov 9 | > 10 | > Permission is hereby granted, free of charge, to any person obtaining 11 | > a copy of this software and associated documentation files (the 12 | > "Software"), to deal in the Software without restriction, including 13 | > without limitation the rights to use, copy, modify, merge, publish, 14 | > distribute, sublicense, and/or sell copies of the Software, and to 15 | > permit persons to whom the Software is furnished to do so, subject to 16 | > the following conditions: 17 | > 18 | > The above copyright notice and this permission notice shall be 19 | > included in all copies or substantial portions of the Software. 20 | > 21 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | 29 | 30 | ## Kingfisher 31 | 32 | The MIT License (MIT) 33 | 34 | Copyright (c) 2019 Wei Wang 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | copies of the Software, and to permit persons to whom the Software is 41 | furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all 44 | copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | SOFTWARE. 53 | 54 | 55 | Generated by CocoaPods - https://cocoapods.org 56 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Licensed under the **MIT** license 18 | 19 | > Copyright (c) 2015 Vadym Markov 20 | > 21 | > Permission is hereby granted, free of charge, to any person obtaining 22 | > a copy of this software and associated documentation files (the 23 | > "Software"), to deal in the Software without restriction, including 24 | > without limitation the rights to use, copy, modify, merge, publish, 25 | > distribute, sublicense, and/or sell copies of the Software, and to 26 | > permit persons to whom the Software is furnished to do so, subject to 27 | > the following conditions: 28 | > 29 | > The above copyright notice and this permission notice shall be 30 | > included in all copies or substantial portions of the Software. 31 | > 32 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 33 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 34 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 35 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 36 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 37 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 38 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 39 | 40 | License 41 | MIT 42 | Title 43 | Fakery 44 | Type 45 | PSGroupSpecifier 46 | 47 | 48 | FooterText 49 | The MIT License (MIT) 50 | 51 | Copyright (c) 2019 Wei Wang 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a copy 54 | of this software and associated documentation files (the "Software"), to deal 55 | in the Software without restriction, including without limitation the rights 56 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 57 | copies of the Software, and to permit persons to whom the Software is 58 | furnished to do so, subject to the following conditions: 59 | 60 | The above copyright notice and this permission notice shall be included in all 61 | copies or substantial portions of the Software. 62 | 63 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 66 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 67 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 68 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 69 | SOFTWARE. 70 | 71 | 72 | License 73 | MIT 74 | Title 75 | Kingfisher 76 | Type 77 | PSGroupSpecifier 78 | 79 | 80 | FooterText 81 | Generated by CocoaPods - https://cocoapods.org 82 | Title 83 | 84 | Type 85 | PSGroupSpecifier 86 | 87 | 88 | StringsTable 89 | Acknowledgements 90 | Title 91 | Acknowledgements 92 | 93 | 94 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_DynamicCell : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_DynamicCell 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Fakery/Fakery.framework 3 | ${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Fakery.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Fakery/Fakery.framework 3 | ${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Fakery.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_DynamicCellVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_DynamicCellVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery/Fakery.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" -framework "Fakery" -framework "Foundation" -framework "Kingfisher" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_DynamicCell { 2 | umbrella header "Pods-DynamicCell-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCell/Pods-DynamicCell.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery/Fakery.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" -framework "Fakery" -framework "Foundation" -framework "Kingfisher" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_DynamicCellTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_DynamicCellTests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_DynamicCellTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_DynamicCellTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery/Fakery.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" -framework "Fakery" -framework "Foundation" -framework "Kingfisher" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_DynamicCellTests { 2 | umbrella header "Pods-DynamicCellTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DynamicCellTests/Pods-DynamicCellTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Fakery/Fakery.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "CFNetwork" -framework "Fakery" -framework "Foundation" -framework "Kingfisher" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DynamicCell 2 | How to implement a dynamic height UICollectionViewCell in Swift. 3 | 4 | This tutorial has two parts. First, We're going to implement a self-sizing UICollectionViewCell based on font size as shown in the screenshot on the left side. 5 | Second, we're going to build a dynamic height UICollectionViewCell based on the image aspect ratio in addition to font size the result will be like the right side of the screenshot. 6 | 7 | ![113447990-9d4fd680-9403-11eb-8e2a-2852a6af3656](https://user-images.githubusercontent.com/71793823/174886656-c0a5ff22-1e6f-4376-8d2e-4c9d53c39210.png) 8 | 9 | ## Tutorial 10 | [The Article on Meduim](https://medium.com/post/bdd912acd5c8) 11 | 12 | ## Prerequisites 13 | * Swift 5.3 14 | * Xcode 15 | * CocoaPods 16 | 17 | ## Technology used 18 | * Xcode 19 | * Swift 5.3 20 | 21 | ## How to use ? 22 | 1. Download or clone the repository. 23 | 2. Open the project through Xcode. 24 | 3. Run the application in mobile or simulator running iOS 13 25 | 26 | ## Credits 27 | © Mohannad BakBouk | 2021 28 | 29 | --------------------------------------------------------------------------------