├── Cartfile ├── .gitignore ├── Cartfile.resolved ├── Mensa ├── Dependencies │ ├── Model.swift │ ├── View.swift │ └── Controller.swift ├── Sources │ ├── Controller │ │ ├── Identifier │ │ │ ├── Identifier.swift │ │ │ ├── ItemTypeIdentifier.swift │ │ │ └── ItemTypeVariantIdentifier.swift │ │ ├── Interface │ │ │ ├── ItemInterfacing.swift │ │ │ └── DataInterfacing.swift │ │ └── Mediator │ │ │ ├── ItemMediator.swift │ │ │ └── DataMediator.swift │ ├── View │ │ ├── Hosting │ │ │ ├── Table View │ │ │ │ ├── HostingHeaderFooterView.swift │ │ │ │ ├── HostingTableViewCell.swift │ │ │ │ └── HostingTableView.swift │ │ │ ├── HostingStrategy.swift │ │ │ ├── Collection View │ │ │ │ ├── HostingSupplementaryView.swift │ │ │ │ ├── HostingCollectionViewCell.swift │ │ │ │ └── HostingCollectionView.swift │ │ │ └── HostingView.swift │ │ ├── Reusable │ │ │ └── ReusableView.swift │ │ ├── Display │ │ │ ├── DataDisplayContext.swift │ │ │ ├── DataDisplaying.swift │ │ │ └── ItemDisplaying.swift │ │ └── Scrolling │ │ │ └── ScrollEvent.swift │ └── Model │ │ └── Data │ │ ├── SectionIndexPath.swift │ │ ├── MutableDataSource.swift │ │ ├── ItemPosition.swift │ │ ├── Section.swift │ │ ├── SingleSectionDataSource.swift │ │ ├── MutableSingleSectionDataSource.swift │ │ └── DataSource.swift └── Resources │ └── Info.plist ├── Mensa.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ ├── jkay010.xcuserdatad │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── Jordan.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── project.pbxproj └── LICENSE /Cartfile: -------------------------------------------------------------------------------- 1 | github "CultivR/Tangram" "0.2.0/view" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | Carthage 3 | xcuserdata 4 | xcuserstate 5 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "CultivR/Tangram" "93175305a7bc397d8975009fc9a629ec4ae42b64" 2 | -------------------------------------------------------------------------------- /Mensa/Dependencies/Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Mensa.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/16/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | -------------------------------------------------------------------------------- /Mensa.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Mensa/Dependencies/View.swift: -------------------------------------------------------------------------------- 1 | // 2 | // View.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 3/27/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | @_exported import UIKit 10 | @_exported import Tangram 11 | -------------------------------------------------------------------------------- /Mensa/Dependencies/Controller.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Controller.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | @_exported import UIKit 10 | @_exported import Tangram 11 | -------------------------------------------------------------------------------- /Mensa/Sources/Controller/Identifier/Identifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Identifier.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/22/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | protocol Identifier: Hashable { 10 | var value: String { get } 11 | } 12 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/Table View/HostingHeaderFooterView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderFooterView.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 5/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | class HostingHeaderFooterView: UITableViewHeaderFooterView {} 10 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/HostingStrategy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HostingStrategy.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 6/7/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | enum HostingStrategy { 10 | case itemSize 11 | case viewSize 12 | case pinToEdges 13 | } 14 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Reusable/ReusableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReusableView.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 5/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | //public protocol ReusableView: UIView { 10 | // var viewController: UIViewController! { get set } 11 | //} 12 | -------------------------------------------------------------------------------- /Mensa.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Mensa/Sources/Model/Data/SectionIndexPath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionIndexPath.swift 3 | // Model 4 | // 5 | // Created by Jordan Kay on 4/16/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | protocol SectionIndexPath { 10 | var section: Int { get } 11 | var row: Int { get } 12 | var item: Int { get } 13 | } 14 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Display/DataDisplayContext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataDisplayContext.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 5/8/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public enum DataDisplayContext { 10 | case tableView 11 | case collectionView(layout: UICollectionViewLayout) 12 | } 13 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Scrolling/ScrollEvent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScrollEvent.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 6/5/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public enum ScrollEvent { 10 | case didScroll 11 | case willEndDragging(velocity: CGPoint, targetContentOffset: CGPoint) 12 | case didEndDecelerating 13 | case didEndScrollingAnimation 14 | } 15 | -------------------------------------------------------------------------------- /Mensa/Sources/Controller/Identifier/ItemTypeIdentifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ItemTypeIdentifier.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/22/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | struct ItemTypeIdentifier { 10 | let value: String 11 | 12 | init(itemType: Any.Type) { 13 | value = String(describing: itemType) 14 | } 15 | } 16 | 17 | extension ItemTypeIdentifier: Identifier {} 18 | -------------------------------------------------------------------------------- /Mensa/Sources/Controller/Identifier/ItemTypeVariantIdentifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ItemTypeVariantIdentifier.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/22/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | struct ItemTypeVariantIdentifier { 10 | let value: String 11 | 12 | init(itemTypeIdentifier: ItemTypeIdentifier, variant: Variant) { 13 | value = itemTypeIdentifier.value + variant.name 14 | } 15 | } 16 | 17 | extension ItemTypeVariantIdentifier: Identifier {} 18 | -------------------------------------------------------------------------------- /Mensa/Sources/Model/Data/MutableDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MutableDataSource.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 6/5/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public protocol MutableDataSource: DataSource where Item: Equatable { 10 | var sections: [Section] { get set } 11 | } 12 | 13 | // MARK: - 14 | extension MutableDataSource { 15 | mutating func setItem(_ item: Item, at indexPath: IndexPath) { 16 | sections[indexPath.section][indexPath.row] = item 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Mensa.xcodeproj/xcuserdata/jkay010.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Mensa.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | MensaExample.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/Collection View/HostingSupplementaryView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SupplementaryView.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 5/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | class HostingSupplementaryView: UICollectionReusableView { 10 | weak var viewController: UIViewController! 11 | } 12 | 13 | // MARK: - 14 | extension HostingSupplementaryView: HostingView { 15 | var contentView: UIView { 16 | return self 17 | } 18 | 19 | func addSizeConstraints(toHostedView hostedView: UIView) { 20 | return 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Display/DataDisplaying.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataDisplaying.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | protocol DataDisplaying: UIScrollView { 10 | var retainedDelegate: UIScrollViewDelegate { get } 11 | 12 | func reloadData() 13 | 14 | func register(_ hostingViewType: HostingView.Type, reuseIdentifier: String) 15 | func register(_ headerFooterViewType: HostingHeaderFooterView.Type, reuseIdentifier: String) 16 | func register(_ supplementaryViewType: HostingSupplementaryView.Type, reuseIdentifier: String) 17 | } 18 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/Table View/HostingTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HostingTableViewCell.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | final class HostingTableViewCell: UITableViewCell { 10 | weak var viewController: UIViewController! 11 | } 12 | 13 | // MARK: - 14 | extension HostingTableViewCell: HostingView { 15 | func addSizeConstraints(toHostedView hostedView: UIView) { 16 | let heightConstraint = NSLayoutConstraint(item: hostedView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: hostedView.bounds.height) 17 | hostedView.addConstraint(heightConstraint) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Mensa/Sources/Model/Data/ItemPosition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ItemPosition.swift 3 | // Model 4 | // 5 | // Created by Jordan Kay on 5/14/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public enum ItemPosition: String { 10 | case top 11 | case middle 12 | case bottom 13 | case lone 14 | } 15 | 16 | // MARK: - 17 | extension ItemPosition { 18 | init(indexPath: SectionIndexPath, itemCount: Int) { 19 | switch indexPath.item { 20 | case 0: 21 | self = (itemCount == 1) ? .lone : .top 22 | case itemCount - 1: 23 | self = .bottom 24 | default: 25 | self = .middle 26 | } 27 | } 28 | } 29 | 30 | // MARK: - 31 | extension ItemPosition: CaseIterable {} 32 | -------------------------------------------------------------------------------- /Mensa/Sources/Model/Data/Section.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Section.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public struct Section { 10 | let header: Header? 11 | var items: [Item] 12 | 13 | public init(header: Header? = nil, items: [Item]) { 14 | self.items = items 15 | self.header = header 16 | } 17 | } 18 | 19 | // MARK: - 20 | extension Section { 21 | var itemCount: Int { 22 | return items.count 23 | } 24 | 25 | subscript(index: Int) -> Item { 26 | get { 27 | return items[index] 28 | } 29 | set { 30 | items[index] = newValue 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Mensa/Sources/Model/Data/SingleSectionDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SingleSectionDataSource.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public protocol SingleSectionDataSource: DataSource { 10 | var items: [Item] { get } 11 | var header: Header? { get } 12 | } 13 | 14 | // MARK: - 15 | public extension SingleSectionDataSource { 16 | var header: Header? { 17 | return nil 18 | } 19 | 20 | func item(at index: Int) -> Item? { 21 | guard index >= 0, index < items.count else { return nil } 22 | return items[index] 23 | } 24 | 25 | // MARK: DataSource 26 | var sections: [Section] { 27 | return [.init(header: header, items: items)] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Mensa/Resources/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 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Mensa/Sources/Model/Data/MutableSingleSectionDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MutableSingleSectionDataSource.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 6/5/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public protocol MutableSingleSectionDataSource: MutableDataSource { 10 | var items: [Item] { get set } 11 | } 12 | 13 | // MARK: - 14 | public extension MutableSingleSectionDataSource { 15 | var header: Header? { 16 | return nil 17 | } 18 | 19 | func item(at index: Int) -> Item? { 20 | guard index >= 0, index < items.count else { return nil } 21 | return items[index] 22 | } 23 | 24 | // MARK: DataSource 25 | var sections: [Section] { 26 | get { 27 | return [.init(header: header, items: items)] 28 | } 29 | set { 30 | guard let section = newValue.first else { return } 31 | items = section.items 32 | } 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/Collection View/HostingCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HostingCollectionViewCell.swift 3 | // Mensan 4 | // 5 | // Created by Jordan Kay on 5/7/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | final class HostingCollectionViewCell: UICollectionViewCell { 10 | weak var viewController: UIViewController! 11 | } 12 | 13 | // MARK: - 14 | extension HostingCollectionViewCell: HostingView { 15 | func addSizeConstraints(toHostedView hostedView: UIView) { 16 | let widthConstraint = NSLayoutConstraint(item: hostedView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: hostedView.bounds.width) 17 | let heightConstraint = NSLayoutConstraint(item: hostedView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: hostedView.bounds.height) 18 | let constraints = [widthConstraint, heightConstraint] 19 | hostedView.addConstraints(constraints) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Mensa.xcodeproj/xcuserdata/Jordan.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Controller.xcscheme 8 | 9 | orderHint 10 | 2 11 | 12 | MensaExample.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | Model.xcscheme 18 | 19 | orderHint 20 | 0 21 | 22 | View.xcscheme 23 | 24 | orderHint 25 | 1 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 17DFC9EF225E7E9C00871C7D 31 | 32 | primary 33 | 34 | 35 | 17F803042255940300212525 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Mensa/Sources/Model/Data/DataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataSource.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/3/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public protocol DataSource { 10 | associatedtype Item 11 | associatedtype Header 12 | 13 | var sections: [Section] { get } 14 | } 15 | 16 | // MARK: - 17 | extension DataSource { 18 | func item(at indexPath: IndexPath) -> Item { 19 | return sections[indexPath.section][indexPath.row] 20 | } 21 | 22 | func header(for section: Int) -> Header? { 23 | return sections[section].header 24 | } 25 | } 26 | 27 | // MARK: - 28 | extension DataSource where Item: Equatable { 29 | func indexPath(for item: Item) -> IndexPath? { 30 | for (sectionIndex, section) in sections.enumerated() { 31 | for (itemIndex, sectionItem) in section.items.enumerated() { 32 | if item == sectionItem { 33 | return IndexPath(item: itemIndex, section: sectionIndex) 34 | } 35 | } 36 | } 37 | return nil 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 CultivR 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 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Display/ItemDisplaying.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ItemDisplaying.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public protocol ItemDisplaying: CustomDisplaying { 10 | typealias Item = Model 11 | 12 | static var itemDisplayVariants: [DisplayVariant] { get } 13 | 14 | func setHighlighted(_ highlighted: Bool, animated: Bool) 15 | } 16 | 17 | // MARK: - 18 | public extension ItemDisplaying { 19 | func setHighlighted(_ highlighted: Bool, animated: Bool) { 20 | return 21 | } 22 | } 23 | 24 | // MARK: - 25 | public extension ItemDisplaying where DisplayVariant == Invariant { 26 | static var defaultVariant: Invariant { 27 | return .init() 28 | } 29 | 30 | static var itemDisplayVariants: [Invariant] { 31 | return [.init()] 32 | } 33 | } 34 | 35 | public extension ItemDisplaying where DisplayVariant: CaseIterable, DisplayVariant.AllCases == [DisplayVariant] { 36 | static var itemDisplayVariants: [DisplayVariant] { 37 | return DisplayVariant.allCases 38 | } 39 | } 40 | 41 | // MARK: - 42 | extension ItemPosition: Variant {} 43 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/Table View/HostingTableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HostingTableView.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/12/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | final class HostingTableView: UITableView { 10 | let retainedDelegate: UIScrollViewDelegate 11 | 12 | init(frame: CGRect, delegate: UITableViewDelegate) { 13 | retainedDelegate = delegate 14 | super.init(frame: frame, style: .plain) 15 | self.delegate = delegate 16 | autoresizingMask = [.flexibleWidth, .flexibleHeight] 17 | } 18 | 19 | required init?(coder: NSCoder) { 20 | fatalError() 21 | } 22 | } 23 | 24 | // MARK: - 25 | extension HostingTableView: DataDisplaying { 26 | // MARK: DataDisplaying 27 | func register(_ hostingViewType: HostingView.Type, reuseIdentifier: String) { 28 | register(hostingViewType, forCellReuseIdentifier: reuseIdentifier) 29 | } 30 | 31 | func register(_ headerFooterViewType: HostingHeaderFooterView.Type, reuseIdentifier: String) { 32 | register(headerFooterViewType, forHeaderFooterViewReuseIdentifier: reuseIdentifier) 33 | } 34 | 35 | func register(_ supplementaryViewType: HostingSupplementaryView.Type, reuseIdentifier: String) { 36 | return 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Mensa/Sources/Controller/Interface/ItemInterfacing.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ItemInterfacing.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public protocol ItemInterfacing: UIViewController { 10 | associatedtype View: ItemDisplaying 11 | 12 | func interface(with item: View.Item) 13 | func set(_ item: View.Item, selected: Bool) 14 | func select(_ item: View.Item) 15 | func deselect(_ item: View.Item) 16 | func shouldSelect(_ item: View.Item) -> Bool 17 | func prepareToSelect(_ item: View.Item) 18 | } 19 | 20 | public extension ItemInterfacing { 21 | var view: View { 22 | return view as! View 23 | } 24 | 25 | func interface(with item: View.Item) { 26 | view.display(item) 27 | } 28 | 29 | func set(_ item: View.Item, selected: Bool) { 30 | if selected { 31 | select(item) 32 | } else { 33 | deselect(item) 34 | } 35 | } 36 | 37 | func select(_ item: View.Item) { 38 | return 39 | } 40 | 41 | func deselect(_ item: View.Item) { 42 | return 43 | } 44 | 45 | func shouldSelect(_ item: View.Item) -> Bool { 46 | return true 47 | } 48 | 49 | func prepareToSelect(_ item: View.Item) { 50 | return 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/Collection View/HostingCollectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HostingCollectionView.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 5/7/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | final class HostingCollectionView: UICollectionView { 10 | let retainedDelegate: UIScrollViewDelegate 11 | 12 | init(frame: CGRect, layout: UICollectionViewLayout, delegate: UICollectionViewDelegate) { 13 | retainedDelegate = delegate 14 | super.init(frame: frame, collectionViewLayout: layout) 15 | self.delegate = delegate 16 | 17 | backgroundColor = .clear 18 | isPrefetchingEnabled = false 19 | autoresizingMask = [.flexibleWidth, .flexibleHeight] 20 | } 21 | 22 | required init?(coder: NSCoder) { 23 | fatalError() 24 | } 25 | } 26 | 27 | // MARK: - 28 | extension HostingCollectionView: DataDisplaying { 29 | // MARK: DataDisplaying 30 | func register(_ hostingViewType: HostingView.Type, reuseIdentifier: String) { 31 | register(hostingViewType, forCellWithReuseIdentifier: reuseIdentifier) 32 | } 33 | 34 | func register(_ headerFooterViewType: HostingHeaderFooterView.Type, reuseIdentifier: String) { 35 | return 36 | } 37 | 38 | func register(_ supplementaryViewType: HostingSupplementaryView.Type, reuseIdentifier: String) { 39 | register(supplementaryViewType, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: reuseIdentifier) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Mensa/Sources/Controller/Mediator/ItemMediator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyItemInterfacing.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/11/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | struct ItemMediator { 10 | let displayVariant: Variant 11 | let interface: (UIViewController, Any) -> Void 12 | let setSelected: (UIViewController, Any, Bool) -> Void 13 | let shouldSelect: (UIViewController, Any) -> Bool 14 | let prepareToSelect: (UIViewController, Any) -> Void 15 | let highlight: (UIViewController, Bool, Bool) -> Void 16 | } 17 | 18 | // MARK: - 19 | extension ItemMediator { 20 | init(interfaceType: Interface.Type, displayVariant: Interface.View.DisplayVariant, dataInterface: DataInterface) { 21 | self.displayVariant = displayVariant 22 | interface = { [weak dataInterface] in 23 | guard let dataInterface = dataInterface else { return } 24 | 25 | let viewController = $0 as! Interface 26 | let item = $1 as! Interface.View.Item 27 | 28 | if let item = item as? DataInterface.Item, let viewController = viewController as? DataInterface.ItemViewController { 29 | dataInterface.handleDisplayingItem(item, using: viewController) 30 | } else if let header = item as? DataInterface.Header, let viewController = viewController as? DataInterface.HeaderViewController { 31 | dataInterface.handleDisplayingHeader(header, using: viewController) 32 | } 33 | viewController.interface(with: item) 34 | } 35 | setSelected = { 36 | let viewController = $0 as! Interface 37 | let item = $1 as! Interface.View.Item 38 | let selected = $2 39 | viewController.set(item, selected: selected) 40 | } 41 | shouldSelect = { 42 | let viewController = $0 as! Interface 43 | let item = $1 as! Interface.View.Item 44 | return viewController.shouldSelect(item) 45 | } 46 | prepareToSelect = { 47 | let viewController = $0 as! Interface 48 | let item = $1 as! Interface.View.Item 49 | viewController.prepareToSelect(item) 50 | } 51 | highlight = { 52 | let viewController = $0 as! Interface 53 | let view: Interface.View = viewController.view 54 | view.setHighlighted($1, animated: $2) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Mensa/Sources/View/Hosting/HostingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Hosting.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | protocol HostingView: UIView { 10 | var contentView: UIView { get } 11 | var viewController: UIViewController! { get set } 12 | 13 | func addSizeConstraints(toHostedView hostedView: UIView) 14 | } 15 | 16 | // MARK: - 17 | extension HostingView { 18 | func hostContent(of type: NibLoadable.Type, from viewController: UIViewController, with variant: Variant) { 19 | let hostedView = type.hostedView(of: variant) 20 | hostedView.backgroundColor = .clear 21 | hostedView.frame.size.width = contentView.bounds.width 22 | viewController.view = hostedView 23 | viewController.viewDidLoad() 24 | self.viewController = viewController 25 | 26 | contentView.addSubview(hostedView) 27 | addEdgeConstraints(toHostedView: hostedView) 28 | } 29 | } 30 | 31 | // MARK: - 32 | private extension HostingView { 33 | func addEdgeConstraints(toHostedView hostedView: UIView) { 34 | for attribute: NSLayoutConstraint.Attribute in [.top, .left, .bottom, .right] { 35 | let constraint = NSLayoutConstraint(item: contentView, attribute: attribute, relatedBy: .equal, toItem: hostedView, attribute: attribute, multiplier: 1, constant: 0) 36 | if attribute == .bottom { 37 | constraint.priority -= 1 38 | } 39 | contentView.addConstraint(constraint) 40 | } 41 | } 42 | 43 | func addPinConstraints(withWidth width: CGFloat, toHostedView hostedView: UIView) { 44 | let widthConstraint = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: 1, constant: width) 45 | let heightConstraint = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: bounds.height) 46 | addConstraint(widthConstraint) 47 | addConstraint(heightConstraint) 48 | 49 | for attribute: NSLayoutConstraint.Attribute in [.top, .bottom,] { 50 | let constraint = NSLayoutConstraint(item: contentView, attribute: attribute, relatedBy: .equal, toItem: hostedView, attribute: attribute, multiplier: 1, constant: 0) 51 | if attribute == .bottom { 52 | constraint.priority -= 1 53 | } 54 | contentView.addConstraint(constraint) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Mensa/Sources/Controller/Interface/DataInterfacing.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataInterfacing.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | public protocol DataInterfacing: UIViewController, UIScrollViewDelegate { 10 | typealias Item = DataSourceType.Item 11 | typealias Header = DataSourceType.Header 12 | 13 | associatedtype DataSourceType: DataSource 14 | associatedtype ItemViewController: UIViewController = UIViewController 15 | associatedtype HeaderViewController: UIViewController = UIViewController 16 | 17 | var displayContext: DataDisplayContext { get } 18 | 19 | func displayVariant(for item: Item, at position: ItemPosition) -> Variant? 20 | func displayVariant(for header: Header) -> Variant? 21 | func prepareAndAddDataView(_ dataView: UIScrollView) 22 | func supportInterfacingWithData() 23 | func handleDisplayingItem(_ item: Item, using viewController: ItemViewController) 24 | func handleDisplayingHeader(_ header: Header, using viewController: HeaderViewController) 25 | func handle(_ scrollEvent: ScrollEvent, for scrollView: UIScrollView) 26 | } 27 | 28 | public extension DataInterfacing { 29 | var dataSource: DataSourceType? { 30 | return dataMediator?.dataSource 31 | } 32 | 33 | var scrollView: UIScrollView? { 34 | return dataView 35 | } 36 | 37 | var selectedItem: Item? { 38 | return dataMediator?.selectedIndexPath.flatMap { dataSource?.item(at: $0) } 39 | } 40 | 41 | func useData(from dataSource: DataSourceType, reload: Bool = true) { 42 | if let dataView = dataView { 43 | dataMediator.dataSource = dataSource 44 | if reload { 45 | dataView.reloadData() 46 | } 47 | } else { 48 | setupDataView() 49 | supportInterfacingWithData() 50 | 51 | dataView!.registerIdentifiers(for: displayContext, using: dataMediator) 52 | dataMediator.dataSource = dataSource 53 | } 54 | } 55 | 56 | // MARK: DataInterfacing 57 | func displayVariant(for item: Item, at position: ItemPosition) -> Variant? { 58 | return nil 59 | } 60 | 61 | func displayVariant(for header: Header) -> Variant? { 62 | return nil 63 | } 64 | 65 | func prepareAndAddDataView(_ dataView: UIScrollView) { 66 | dataView.alwaysBounceVertical = true 67 | view.addSubview(dataView) 68 | } 69 | 70 | func supportInterfacing(with itemType: Interface.View.Item.Type, conformedToBy conformingTypes: Any.Type..., using interfaceType: Interface.Type) { 71 | if conformingTypes.count > 0 { 72 | conformingTypes.forEach { 73 | dataMediator.supportInterfacing(with: $0, using: interfaceType) 74 | } 75 | } else { 76 | dataMediator.supportInterfacing(with: itemType, using: interfaceType) 77 | } 78 | } 79 | 80 | func handleDisplayingItem(_ item: Item, using viewController: ItemViewController) { 81 | return 82 | } 83 | 84 | func handleDisplayingHeader(_ header: Header, using viewController: HeaderViewController) { 85 | return 86 | } 87 | 88 | func handle(_ scrollEvent: ScrollEvent, for scrollView: UIScrollView) { 89 | return 90 | } 91 | } 92 | 93 | public extension DataInterfacing where Item: Equatable { 94 | func select(_ item: Item) { 95 | guard let indexPath = dataSource?.indexPath(for: item) else { return } 96 | 97 | dataMediator?.selectedIndexPath = indexPath 98 | } 99 | 100 | func select(_ item: Item, scrollPosition: UICollectionView.ScrollPosition, animated: Bool) { 101 | guard let indexPath = dataSource?.indexPath(for: item) else { return } 102 | 103 | position(item, at: scrollPosition, animated: animated) 104 | dataMediator?.selectedIndexPath = indexPath 105 | } 106 | 107 | func position(_ item: Item, at scrollPosition: UICollectionView.ScrollPosition, animated: Bool) { 108 | guard let indexPath = dataSource?.indexPath(for: item), let collectionView = collectionView else { return } 109 | 110 | collectionView.scrollToItem(at: indexPath, at: scrollPosition, animated: animated) 111 | } 112 | } 113 | 114 | public extension DataInterfacing where DataSourceType: MutableDataSource { 115 | func replace(_ item: Item, with replacementItem: Item) { 116 | guard let indexPath = dataSource?.indexPath(for: item) else { return } 117 | 118 | dataMediator?.dataSource?.setItem(replacementItem, at: indexPath) 119 | if let collectionView = collectionView { 120 | UIView.performWithoutAnimation { 121 | collectionView.reloadItems(at: [indexPath]) 122 | } 123 | } 124 | } 125 | } 126 | 127 | private extension DataInterfacing { 128 | var dataView: DataDisplaying? { 129 | get { 130 | return objc_getAssociatedObject(self, &key) as? DataDisplaying 131 | } 132 | set { 133 | objc_setAssociatedObject(self, &key, newValue, .OBJC_ASSOCIATION_RETAIN) 134 | } 135 | } 136 | 137 | var tableView: UITableView? { 138 | return dataView as? UITableView 139 | } 140 | 141 | var collectionView: UICollectionView? { 142 | return dataView as? UICollectionView 143 | } 144 | 145 | var dataMediator: DataMediator! { 146 | return tableView?.delegate as? DataMediator ?? collectionView?.delegate as? DataMediator 147 | } 148 | 149 | func setupDataView() { 150 | let dataMediator = DataMediator(dataInterface: self) 151 | 152 | switch displayContext { 153 | case .tableView: 154 | setupTableView(with: dataMediator) 155 | case let .collectionView(layout): 156 | setupCollectionViewWith(dataMediator: dataMediator, layout: layout) 157 | } 158 | } 159 | 160 | func setupTableView(with dataMediator: DataMediator) { 161 | let tableView = HostingTableView(frame: view.bounds, delegate: dataMediator) 162 | tableView.dataSource = dataMediator 163 | dataView = tableView 164 | prepareAndAddDataView(tableView) 165 | } 166 | 167 | func setupCollectionViewWith(dataMediator: DataMediator, layout: UICollectionViewLayout) { 168 | let collectionView = HostingCollectionView(frame: view.bounds, layout: layout, delegate: dataMediator) 169 | collectionView.dataSource = dataMediator 170 | dataView = collectionView 171 | prepareAndAddDataView(collectionView) 172 | } 173 | } 174 | 175 | private extension DataDisplaying { 176 | func registerIdentifiers(for displayContext: DataDisplayContext, using dataMediator: DataMediator) { 177 | let identifiers = dataMediator.itemTypeVariantIdentifiers 178 | identifiers.forEach { register($0, for: displayContext) } 179 | } 180 | 181 | func register(_ identifier: ItemTypeVariantIdentifier, for displayContext: DataDisplayContext) { 182 | let reuseIdentifier = identifier.value 183 | switch displayContext { 184 | case .tableView: 185 | register(HostingTableViewCell.self, reuseIdentifier: reuseIdentifier) 186 | register(HostingHeaderFooterView.self, reuseIdentifier: reuseIdentifier) 187 | case .collectionView: 188 | register(HostingCollectionViewCell.self, reuseIdentifier: reuseIdentifier) 189 | register(HostingSupplementaryView.self, reuseIdentifier: reuseIdentifier) 190 | } 191 | } 192 | } 193 | 194 | // MARK: - 195 | private var key: Void? 196 | -------------------------------------------------------------------------------- /Mensa/Sources/Controller/Mediator/DataMediator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataMediator.swift 3 | // Mensa 4 | // 5 | // Created by Jordan Kay on 4/10/19. 6 | // Copyright © 2019 CultivR. All rights reserved. 7 | // 8 | 9 | final class DataMediator: NSObject, UITableViewDelegate, UITableViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource { 10 | typealias Item = DataInterface.DataSourceType.Item 11 | typealias Header = DataInterface.DataSourceType.Header 12 | 13 | var dataSource: DataInterface.DataSourceType? 14 | var selectedIndexPath: IndexPath? 15 | 16 | private var defaultDisplayVariants: [ItemTypeIdentifier: Variant] = [:] 17 | private var itemMediators: [ItemTypeVariantIdentifier: ItemMediator] = [:] 18 | private var viewControllerTypes: [ItemTypeVariantIdentifier: UIViewController.Type] = [:] 19 | private var registeredSupplementaryViewIdentifiers: Set = [] 20 | private var headerHeightCache: [Int: CGFloat] = [:] 21 | 22 | private weak var dataInterface: DataInterface! 23 | 24 | init(dataInterface: DataInterface) { 25 | self.dataInterface = dataInterface 26 | } 27 | 28 | // MARK: UIScrollViewDelegate 29 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 30 | dataInterface.handle(.didScroll, for: scrollView) 31 | } 32 | 33 | func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { 34 | let scrollEvent = ScrollEvent.willEndDragging(velocity: velocity, targetContentOffset: targetContentOffset.pointee) 35 | dataInterface.handle(scrollEvent, for: scrollView) 36 | } 37 | 38 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { 39 | dataInterface.handle(.didEndDecelerating, for: scrollView) 40 | } 41 | 42 | func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { 43 | dataInterface.handle(.didEndScrollingAnimation, for: scrollView) 44 | } 45 | 46 | // MARK: UITableViewDataSource 47 | func numberOfSections(in tableView: UITableView) -> Int { 48 | return sectionCount 49 | } 50 | 51 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 52 | return itemCount(forSection: section) 53 | } 54 | 55 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 56 | let (identifier, itemMediator, item) = info(for: indexPath) 57 | let cell = tableView.dequeueReusableCell(withIdentifier: identifier.value, for: indexPath) as! HostingView 58 | let viewController = cell.viewController ?? hostContent(in: cell, for: identifier) 59 | 60 | itemMediator.interface(viewController, item) 61 | return cell as! UITableViewCell 62 | } 63 | 64 | // MARK: UICollectionViewDataSource 65 | func numberOfSections(in collectionView: UICollectionView) -> Int { 66 | return sectionCount 67 | } 68 | 69 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 70 | return itemCount(forSection: section) 71 | } 72 | 73 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 74 | let (identifier, itemMediator, item) = info(for: indexPath) 75 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier.value, for: indexPath) as! HostingView 76 | let viewController = cell.viewController ?? hostContent(in: cell, for: identifier) 77 | 78 | itemMediator.interface(viewController, item) 79 | return cell as! UICollectionViewCell 80 | } 81 | 82 | func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { 83 | switch kind { 84 | case UICollectionView.elementKindSectionHeader: 85 | guard let (identifier, itemMediator, header) = headerInfo(for: indexPath.section) else { return (nil as UICollectionReusableView?)! } 86 | 87 | let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: identifier.value, for: indexPath) as! HostingView 88 | let viewController = headerView.viewController ?? hostContent(in: headerView, for: identifier) 89 | 90 | itemMediator.interface(viewController, header) 91 | return headerView as! UICollectionReusableView 92 | default: 93 | return (nil as UICollectionReusableView?)! 94 | } 95 | } 96 | 97 | // MARK: UICollectionViewDelegate 98 | func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool { 99 | let (viewController, itemMediator, item) = viewControllerInfo(for: indexPath, in: collectionView) 100 | return itemMediator.shouldSelect(viewController, item) 101 | } 102 | 103 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 104 | let (viewController, itemMediator, item) = viewControllerInfo(for: indexPath, in: collectionView) 105 | 106 | itemMediator.prepareToSelect(viewController, item) 107 | selectedIndexPath = indexPath 108 | itemMediator.setSelected(viewController, item, true) 109 | } 110 | 111 | func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) { 112 | let (viewController, itemMediator, _) = viewControllerInfo(for: indexPath, in: collectionView) 113 | let highlighted = true 114 | let animated = false 115 | 116 | itemMediator.highlight(viewController, highlighted, animated) 117 | } 118 | 119 | func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) { 120 | let (viewController, itemMediator, _) = viewControllerInfo(for: indexPath, in: collectionView) 121 | let highlighted = false 122 | let animated = !collectionView.isDragging 123 | 124 | itemMediator.highlight(viewController, highlighted, animated) 125 | } 126 | 127 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { 128 | guard let (identifier, itemMediator, _) = headerInfo(for: section) else { return .zero } 129 | 130 | let height = headerHeightCache[section] ?? { 131 | let viewControllerType = viewControllerTypes[identifier]! 132 | let viewType = self.viewType(for: viewControllerType) 133 | let displayVariant = itemMediator.displayVariant 134 | let view = viewType.hostedView(of: displayVariant) 135 | let height = view.bounds.height 136 | headerHeightCache[section] = height 137 | return height 138 | }() 139 | 140 | return .init(width: collectionView.bounds.width, height: height) 141 | } 142 | } 143 | 144 | // MARK: - 145 | extension DataMediator { 146 | var itemTypeVariantIdentifiers: [ItemTypeVariantIdentifier] { 147 | return Array(viewControllerTypes.keys) 148 | } 149 | 150 | func supportInterfacing(with itemType: Any.Type, using interfaceType: Interface.Type) { 151 | let variants = Interface.View.itemDisplayVariants 152 | for variant in variants { 153 | let itemTypeIdentifier = ItemTypeIdentifier(itemType: itemType) 154 | let itemTypeVariantIdentifier = ItemTypeVariantIdentifier(itemTypeIdentifier: itemTypeIdentifier, variant: variant) 155 | 156 | defaultDisplayVariants[itemTypeIdentifier] = Interface.View.defaultVariant 157 | itemMediators[itemTypeVariantIdentifier] = .init(interfaceType: interfaceType, displayVariant: variant, dataInterface: dataInterface) 158 | viewControllerTypes[itemTypeVariantIdentifier] = interfaceType 159 | } 160 | } 161 | } 162 | 163 | // MARK: - 164 | private extension DataMediator { 165 | var sectionCount: Int { 166 | let sections = dataSource?.sections 167 | return sections?.count ?? 0 168 | } 169 | 170 | func itemCount(forSection section: Int) -> Int { 171 | let section = dataSource?.sections[section] 172 | return section?.itemCount ?? 0 173 | } 174 | 175 | func info(for indexPath: IndexPath) -> (ItemTypeVariantIdentifier, ItemMediator, Item) { 176 | let item = dataSource!.item(at: indexPath) 177 | let itemType = type(of: item as Any) 178 | let itemTypeIdentifier = ItemTypeIdentifier(itemType: itemType) 179 | let itemCount = self.itemCount(forSection: indexPath.section) 180 | let itemPosition = ItemPosition(indexPath: indexPath, itemCount: itemCount) 181 | let displayVariant = dataInterface.displayVariant(for: item, at: itemPosition) ?? defaultDisplayVariants[itemTypeIdentifier] ?? Invariant() 182 | let itemTypeVariantIdentifier = ItemTypeVariantIdentifier(itemTypeIdentifier: itemTypeIdentifier, variant: displayVariant) 183 | let itemMediator = itemMediators[itemTypeVariantIdentifier]! 184 | return (itemTypeVariantIdentifier, itemMediator, item) 185 | } 186 | 187 | func headerInfo(for section: Int) -> (ItemTypeVariantIdentifier, ItemMediator, Header)? { 188 | guard let header = dataSource!.header(for: section) else { return nil } 189 | 190 | let itemType = type(of: header) 191 | let itemTypeIdentifier = ItemTypeIdentifier(itemType: itemType) 192 | let displayVariant = dataInterface.displayVariant(for: header) ?? defaultDisplayVariants[itemTypeIdentifier] ?? Invariant() 193 | let itemTypeVariantIdentifier = ItemTypeVariantIdentifier(itemTypeIdentifier: itemTypeIdentifier, variant: displayVariant) 194 | let itemMediator = itemMediators[itemTypeVariantIdentifier]! 195 | return (itemTypeVariantIdentifier, itemMediator, header) 196 | } 197 | 198 | func viewControllerInfo(for indexPath: IndexPath, in tableView: UITableView) -> (UIViewController, ItemMediator, Item) { 199 | let (_, itemMediator, item) = info(for: indexPath) 200 | let cell = tableView.cellForRow(at: indexPath) as! HostingView 201 | let viewController = cell.viewController! 202 | return (viewController, itemMediator, item) 203 | } 204 | 205 | func viewControllerInfo(for indexPath: IndexPath, in collectionView: UICollectionView) -> (UIViewController, ItemMediator, Item) { 206 | let (_, itemMediator, item) = info(for: indexPath) 207 | let cell = collectionView.cellForItem(at: indexPath) as! HostingView 208 | let viewController = cell.viewController! 209 | return (viewController, itemMediator, item) 210 | } 211 | 212 | func viewType(for viewControllerType: UIViewController.Type) -> NibLoadable.Type { 213 | let viewControllerName = String(describing: viewControllerType) 214 | let viewName = viewControllerName.replacingOccurrences(of: "Controller", with: "") 215 | return NSClassFromString("View.\(viewName)") as! NibLoadable.Type 216 | } 217 | 218 | func headerIdentifier(for section: Int) -> ItemTypeVariantIdentifier? { 219 | guard let header = dataSource?.sections[section].header else { return nil } 220 | 221 | let headerTypeIdentifier = ItemTypeIdentifier(itemType: type(of: header)) 222 | return .init(itemTypeIdentifier: headerTypeIdentifier, variant: Invariant()) 223 | } 224 | 225 | func hostContent(in hostingView: HostingView, for identifier: ItemTypeVariantIdentifier) -> UIViewController { 226 | let viewControllerType = viewControllerTypes[identifier]! 227 | let viewController = viewControllerType.init() 228 | let viewType = self.viewType(for: viewControllerType) 229 | let hostingViewController = dataInterface as UIViewController 230 | let mediator = itemMediators[identifier]! 231 | let displayVariant = mediator.displayVariant 232 | 233 | hostingView.hostContent(of: viewType, from: viewController, with: displayVariant) 234 | hostingViewController.addChild(viewController) 235 | viewController.didMove(toParent: hostingViewController) 236 | 237 | return viewController 238 | } 239 | } 240 | 241 | // MARK: - 242 | extension IndexPath: SectionIndexPath {} 243 | 244 | private extension CGSize { 245 | static let defaultItemSize: CGSize = .init(width: 50, height: 50) 246 | } 247 | -------------------------------------------------------------------------------- /Mensa.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 172766182255983600C11D4A /* DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172766172255983600C11D4A /* DataSource.swift */; }; 11 | 176A2549226E93100064488F /* Identifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 176A2544226E92990064488F /* Identifier.swift */; }; 12 | 176A254A226E93100064488F /* ItemTypeIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 176A2547226E93040064488F /* ItemTypeIdentifier.swift */; }; 13 | 176A254F226E967A0064488F /* ItemTypeVariantIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 176A254B226E93AA0064488F /* ItemTypeVariantIdentifier.swift */; }; 14 | 17700131228B1BDB006EB3FD /* ItemPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17700130228B1BDB006EB3FD /* ItemPosition.swift */; }; 15 | 17700132228B1C99006EB3FD /* ItemPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17700130228B1BDB006EB3FD /* ItemPosition.swift */; }; 16 | 17700133228B1CA5006EB3FD /* ItemPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17700130228B1BDB006EB3FD /* ItemPosition.swift */; }; 17 | 17718EFC22A834B3004351DE /* ScrollEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718EFA22A834B3004351DE /* ScrollEvent.swift */; }; 18 | 17718EFD22A834BE004351DE /* ScrollEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718EFA22A834B3004351DE /* ScrollEvent.swift */; }; 19 | 17718F0822A855E9004351DE /* MutableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718F0722A855E9004351DE /* MutableDataSource.swift */; }; 20 | 17718F0A22A8563C004351DE /* MutableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718F0722A855E9004351DE /* MutableDataSource.swift */; }; 21 | 17718F0C22A857F2004351DE /* MutableSingleSectionDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718F0B22A857F2004351DE /* MutableSingleSectionDataSource.swift */; }; 22 | 17718F0D22A857F2004351DE /* MutableSingleSectionDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718F0B22A857F2004351DE /* MutableSingleSectionDataSource.swift */; }; 23 | 17718F6422AB2685004351DE /* HostingStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718F6322AB2685004351DE /* HostingStrategy.swift */; }; 24 | 17718F6522AB2685004351DE /* HostingStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17718F6322AB2685004351DE /* HostingStrategy.swift */; }; 25 | 17D4F2352283720D00FDD335 /* DataDisplayContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F2342283720D00FDD335 /* DataDisplayContext.swift */; }; 26 | 17D4F2362283720D00FDD335 /* DataDisplayContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F2342283720D00FDD335 /* DataDisplayContext.swift */; }; 27 | 17D4F27A2285E38700FDD335 /* HostingHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F2792285E38700FDD335 /* HostingHeaderFooterView.swift */; }; 28 | 17D4F27B2285E38700FDD335 /* HostingHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F2792285E38700FDD335 /* HostingHeaderFooterView.swift */; }; 29 | 17D4F27D2285E39500FDD335 /* HostingSupplementaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F27C2285E39400FDD335 /* HostingSupplementaryView.swift */; }; 30 | 17D4F27E2285E39500FDD335 /* HostingSupplementaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F27C2285E39400FDD335 /* HostingSupplementaryView.swift */; }; 31 | 17D4F2802285E8F200FDD335 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F27F2285E8F200FDD335 /* ReusableView.swift */; }; 32 | 17D4F2812285E8F200FDD335 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17D4F27F2285E8F200FDD335 /* ReusableView.swift */; }; 33 | 17DFC9E4225E6D4200871C7D /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFC9E3225E6D4200871C7D /* Section.swift */; }; 34 | 17DFC9E6225E6D8200871C7D /* SingleSectionDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFC9E5225E6D8200871C7D /* SingleSectionDataSource.swift */; }; 35 | 17DFC9F8225E7F2E00871C7D /* Controller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFC9E9225E7E8000871C7D /* Controller.swift */; }; 36 | 17DFC9FA225E7F3600871C7D /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFC9E3225E6D4200871C7D /* Section.swift */; }; 37 | 17DFC9FB225E7F3600871C7D /* DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172766172255983600C11D4A /* DataSource.swift */; }; 38 | 17DFC9FC225E7F3600871C7D /* SingleSectionDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFC9E5225E6D8200871C7D /* SingleSectionDataSource.swift */; }; 39 | 17DFCA02225EA56A00871C7D /* ItemDisplaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFC9FF225EA46400871C7D /* ItemDisplaying.swift */; }; 40 | 17DFCA05225EA9B100871C7D /* ItemInterfacing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA03225EA58000871C7D /* ItemInterfacing.swift */; }; 41 | 17DFCA06225EA9FA00871C7D /* ItemDisplaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFC9FF225EA46400871C7D /* ItemDisplaying.swift */; }; 42 | 17DFCA1D225ECE3A00871C7D /* DataDisplaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA1B225ECE2C00871C7D /* DataDisplaying.swift */; }; 43 | 17DFCA1F225ECEA100871C7D /* DataDisplaying.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA1B225ECE2C00871C7D /* DataDisplaying.swift */; }; 44 | 17DFCA2D225EDA8900871C7D /* DataMediator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA2B225EDA6D00871C7D /* DataMediator.swift */; }; 45 | 17DFCA392260272200871C7D /* ItemMediator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA372260270300871C7D /* ItemMediator.swift */; }; 46 | 17DFCA442261166100871C7D /* DataInterfacing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA09225EAA7000871C7D /* DataInterfacing.swift */; }; 47 | 17DFCA5A2266958800871C7D /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA592266958800871C7D /* Model.swift */; }; 48 | 17DFCA5C22669F7900871C7D /* SectionIndexPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA5B22669F7900871C7D /* SectionIndexPath.swift */; }; 49 | 17DFCA5D22669FB400871C7D /* SectionIndexPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA5B22669F7900871C7D /* SectionIndexPath.swift */; }; 50 | 17F29F0D22825CF0009F5121 /* HostingCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F29F0B22825CEE009F5121 /* HostingCollectionView.swift */; }; 51 | 17F29F0E22825CF1009F5121 /* HostingCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F29F0B22825CEE009F5121 /* HostingCollectionView.swift */; }; 52 | 17F29F1122825CFC009F5121 /* HostingCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F29F0F22825CF9009F5121 /* HostingCollectionViewCell.swift */; }; 53 | 17F29F1222825CFC009F5121 /* HostingCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F29F0F22825CF9009F5121 /* HostingCollectionViewCell.swift */; }; 54 | 17F6A9282266A3C000CBC866 /* HostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA28225ED9C600871C7D /* HostingView.swift */; }; 55 | 17F6A9292266A3C000CBC866 /* HostingTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA40226113F100871C7D /* HostingTableView.swift */; }; 56 | 17F6A92A2266A3C000CBC866 /* HostingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA25225ED98F00871C7D /* HostingTableViewCell.swift */; }; 57 | 17F6A92B2266A3C100CBC866 /* HostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA28225ED9C600871C7D /* HostingView.swift */; }; 58 | 17F6A92C2266A3C100CBC866 /* HostingTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA40226113F100871C7D /* HostingTableView.swift */; }; 59 | 17F6A92D2266A3C100CBC866 /* HostingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17DFCA25225ED98F00871C7D /* HostingTableViewCell.swift */; }; 60 | 17F80310225594A300212525 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1717B5BC224C479100E2ADF3 /* View.swift */; }; 61 | /* End PBXBuildFile section */ 62 | 63 | /* Begin PBXFileReference section */ 64 | 1717B5BC224C479100E2ADF3 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; 65 | 172766172255983600C11D4A /* DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSource.swift; sourceTree = ""; }; 66 | 176A2544226E92990064488F /* Identifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Identifier.swift; sourceTree = ""; }; 67 | 176A2547226E93040064488F /* ItemTypeIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemTypeIdentifier.swift; sourceTree = ""; }; 68 | 176A254B226E93AA0064488F /* ItemTypeVariantIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemTypeVariantIdentifier.swift; sourceTree = ""; }; 69 | 17700130228B1BDB006EB3FD /* ItemPosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemPosition.swift; sourceTree = ""; }; 70 | 17718EFA22A834B3004351DE /* ScrollEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollEvent.swift; sourceTree = ""; }; 71 | 17718F0722A855E9004351DE /* MutableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutableDataSource.swift; sourceTree = ""; }; 72 | 17718F0B22A857F2004351DE /* MutableSingleSectionDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutableSingleSectionDataSource.swift; sourceTree = ""; }; 73 | 17718F6322AB2685004351DE /* HostingStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingStrategy.swift; sourceTree = ""; }; 74 | 1772ABBA1D188BA0007DC99F /* Mensa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mensa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 1772ABBF1D188BA0007DC99F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | 17D4F2342283720D00FDD335 /* DataDisplayContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataDisplayContext.swift; sourceTree = ""; }; 77 | 17D4F2792285E38700FDD335 /* HostingHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingHeaderFooterView.swift; sourceTree = ""; }; 78 | 17D4F27C2285E39400FDD335 /* HostingSupplementaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingSupplementaryView.swift; sourceTree = ""; }; 79 | 17D4F27F2285E8F200FDD335 /* ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusableView.swift; sourceTree = ""; }; 80 | 17DFC9E3225E6D4200871C7D /* Section.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; 81 | 17DFC9E5225E6D8200871C7D /* SingleSectionDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleSectionDataSource.swift; sourceTree = ""; }; 82 | 17DFC9E9225E7E8000871C7D /* Controller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Controller.swift; sourceTree = ""; }; 83 | 17DFC9F0225E7E9C00871C7D /* Mensa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mensa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | 17DFC9FF225EA46400871C7D /* ItemDisplaying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDisplaying.swift; sourceTree = ""; }; 85 | 17DFCA03225EA58000871C7D /* ItemInterfacing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemInterfacing.swift; sourceTree = ""; }; 86 | 17DFCA09225EAA7000871C7D /* DataInterfacing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataInterfacing.swift; sourceTree = ""; }; 87 | 17DFCA1B225ECE2C00871C7D /* DataDisplaying.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataDisplaying.swift; sourceTree = ""; }; 88 | 17DFCA25225ED98F00871C7D /* HostingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingTableViewCell.swift; sourceTree = ""; }; 89 | 17DFCA28225ED9C600871C7D /* HostingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingView.swift; sourceTree = ""; }; 90 | 17DFCA2B225EDA6D00871C7D /* DataMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataMediator.swift; sourceTree = ""; }; 91 | 17DFCA372260270300871C7D /* ItemMediator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemMediator.swift; sourceTree = ""; }; 92 | 17DFCA40226113F100871C7D /* HostingTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingTableView.swift; sourceTree = ""; }; 93 | 17DFCA592266958800871C7D /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; 94 | 17DFCA5B22669F7900871C7D /* SectionIndexPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionIndexPath.swift; sourceTree = ""; }; 95 | 17F29F0B22825CEE009F5121 /* HostingCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingCollectionView.swift; sourceTree = ""; }; 96 | 17F29F0F22825CF9009F5121 /* HostingCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingCollectionViewCell.swift; sourceTree = ""; }; 97 | 17F803052255940300212525 /* Mensa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mensa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 98 | /* End PBXFileReference section */ 99 | 100 | /* Begin PBXFrameworksBuildPhase section */ 101 | 1772ABB61D188BA0007DC99F /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | 17DFC9ED225E7E9C00871C7D /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | ); 113 | runOnlyForDeploymentPostprocessing = 0; 114 | }; 115 | 17F803022255940300212525 /* Frameworks */ = { 116 | isa = PBXFrameworksBuildPhase; 117 | buildActionMask = 2147483647; 118 | files = ( 119 | ); 120 | runOnlyForDeploymentPostprocessing = 0; 121 | }; 122 | /* End PBXFrameworksBuildPhase section */ 123 | 124 | /* Begin PBXGroup section */ 125 | 1717B5B9224C478800E2ADF3 /* Dependencies */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 17DFCA592266958800871C7D /* Model.swift */, 129 | 1717B5BC224C479100E2ADF3 /* View.swift */, 130 | 17DFC9E9225E7E8000871C7D /* Controller.swift */, 131 | ); 132 | path = Dependencies; 133 | sourceTree = ""; 134 | }; 135 | 175B360C1EBD2060004FA581 /* Resources */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 1772ABBF1D188BA0007DC99F /* Info.plist */, 139 | ); 140 | path = Resources; 141 | sourceTree = ""; 142 | }; 143 | 176A2546226E92F90064488F /* Identifier */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 176A2544226E92990064488F /* Identifier.swift */, 147 | 176A2547226E93040064488F /* ItemTypeIdentifier.swift */, 148 | 176A254B226E93AA0064488F /* ItemTypeVariantIdentifier.swift */, 149 | ); 150 | path = Identifier; 151 | sourceTree = ""; 152 | }; 153 | 17718EF922A8349D004351DE /* Scrolling */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 17718EFA22A834B3004351DE /* ScrollEvent.swift */, 157 | ); 158 | path = Scrolling; 159 | sourceTree = ""; 160 | }; 161 | 1772ABB01D188BA0007DC99F = { 162 | isa = PBXGroup; 163 | children = ( 164 | 1772ABBC1D188BA0007DC99F /* Mensa */, 165 | 1772ABBB1D188BA0007DC99F /* Products */, 166 | ); 167 | sourceTree = ""; 168 | }; 169 | 1772ABBB1D188BA0007DC99F /* Products */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 1772ABBA1D188BA0007DC99F /* Mensa.framework */, 173 | 17F803052255940300212525 /* Mensa.framework */, 174 | 17DFC9F0225E7E9C00871C7D /* Mensa.framework */, 175 | ); 176 | name = Products; 177 | sourceTree = ""; 178 | }; 179 | 1772ABBC1D188BA0007DC99F /* Mensa */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 17F8030D2255947300212525 /* Sources */, 183 | 1717B5B9224C478800E2ADF3 /* Dependencies */, 184 | 175B360C1EBD2060004FA581 /* Resources */, 185 | ); 186 | path = Mensa; 187 | sourceTree = ""; 188 | }; 189 | 17D4F2782285E37500FDD335 /* Reusable */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 17D4F27F2285E8F200FDD335 /* ReusableView.swift */, 193 | ); 194 | path = Reusable; 195 | sourceTree = ""; 196 | }; 197 | 17DFC9E2225E6D3100871C7D /* Data */ = { 198 | isa = PBXGroup; 199 | children = ( 200 | 17DFC9E3225E6D4200871C7D /* Section.swift */, 201 | 17DFCA5B22669F7900871C7D /* SectionIndexPath.swift */, 202 | 17700130228B1BDB006EB3FD /* ItemPosition.swift */, 203 | 172766172255983600C11D4A /* DataSource.swift */, 204 | 17718F0722A855E9004351DE /* MutableDataSource.swift */, 205 | 17DFC9E5225E6D8200871C7D /* SingleSectionDataSource.swift */, 206 | 17718F0B22A857F2004351DE /* MutableSingleSectionDataSource.swift */, 207 | ); 208 | path = Data; 209 | sourceTree = ""; 210 | }; 211 | 17DFCA0B225EB8F200871C7D /* Controller */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | 176A2546226E92F90064488F /* Identifier */, 215 | 17DFCA20225ECEAB00871C7D /* Mediator */, 216 | 17DFCA10225EB9BF00871C7D /* Interface */, 217 | ); 218 | path = Controller; 219 | sourceTree = ""; 220 | }; 221 | 17DFCA0C225EB91900871C7D /* Model */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | 17DFC9E2225E6D3100871C7D /* Data */, 225 | ); 226 | path = Model; 227 | sourceTree = ""; 228 | }; 229 | 17DFCA0D225EB92900871C7D /* View */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | 17DFCA23225ED97B00871C7D /* Hosting */, 233 | 17DFCA0F225EB99500871C7D /* Display */, 234 | 17718EF922A8349D004351DE /* Scrolling */, 235 | 17D4F2782285E37500FDD335 /* Reusable */, 236 | ); 237 | path = View; 238 | sourceTree = ""; 239 | }; 240 | 17DFCA0F225EB99500871C7D /* Display */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | 17DFC9FF225EA46400871C7D /* ItemDisplaying.swift */, 244 | 17DFCA1B225ECE2C00871C7D /* DataDisplaying.swift */, 245 | 17D4F2342283720D00FDD335 /* DataDisplayContext.swift */, 246 | ); 247 | path = Display; 248 | sourceTree = ""; 249 | }; 250 | 17DFCA10225EB9BF00871C7D /* Interface */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | 17DFCA03225EA58000871C7D /* ItemInterfacing.swift */, 254 | 17DFCA09225EAA7000871C7D /* DataInterfacing.swift */, 255 | ); 256 | path = Interface; 257 | sourceTree = ""; 258 | }; 259 | 17DFCA20225ECEAB00871C7D /* Mediator */ = { 260 | isa = PBXGroup; 261 | children = ( 262 | 17DFCA372260270300871C7D /* ItemMediator.swift */, 263 | 17DFCA2B225EDA6D00871C7D /* DataMediator.swift */, 264 | ); 265 | path = Mediator; 266 | sourceTree = ""; 267 | }; 268 | 17DFCA23225ED97B00871C7D /* Hosting */ = { 269 | isa = PBXGroup; 270 | children = ( 271 | 17DFCA28225ED9C600871C7D /* HostingView.swift */, 272 | 17718F6322AB2685004351DE /* HostingStrategy.swift */, 273 | 17F29F0922825CB1009F5121 /* Table View */, 274 | 17F29F0A22825CB7009F5121 /* Collection View */, 275 | ); 276 | path = Hosting; 277 | sourceTree = ""; 278 | }; 279 | 17F29F0922825CB1009F5121 /* Table View */ = { 280 | isa = PBXGroup; 281 | children = ( 282 | 17DFCA40226113F100871C7D /* HostingTableView.swift */, 283 | 17DFCA25225ED98F00871C7D /* HostingTableViewCell.swift */, 284 | 17D4F2792285E38700FDD335 /* HostingHeaderFooterView.swift */, 285 | ); 286 | path = "Table View"; 287 | sourceTree = ""; 288 | }; 289 | 17F29F0A22825CB7009F5121 /* Collection View */ = { 290 | isa = PBXGroup; 291 | children = ( 292 | 17F29F0B22825CEE009F5121 /* HostingCollectionView.swift */, 293 | 17F29F0F22825CF9009F5121 /* HostingCollectionViewCell.swift */, 294 | 17D4F27C2285E39400FDD335 /* HostingSupplementaryView.swift */, 295 | ); 296 | path = "Collection View"; 297 | sourceTree = ""; 298 | }; 299 | 17F8030D2255947300212525 /* Sources */ = { 300 | isa = PBXGroup; 301 | children = ( 302 | 17DFCA0C225EB91900871C7D /* Model */, 303 | 17DFCA0D225EB92900871C7D /* View */, 304 | 17DFCA0B225EB8F200871C7D /* Controller */, 305 | ); 306 | path = Sources; 307 | sourceTree = ""; 308 | }; 309 | /* End PBXGroup section */ 310 | 311 | /* Begin PBXHeadersBuildPhase section */ 312 | 1772ABB71D188BA0007DC99F /* Headers */ = { 313 | isa = PBXHeadersBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | 17DFC9EB225E7E9C00871C7D /* Headers */ = { 320 | isa = PBXHeadersBuildPhase; 321 | buildActionMask = 2147483647; 322 | files = ( 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | 17F803002255940300212525 /* Headers */ = { 327 | isa = PBXHeadersBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXHeadersBuildPhase section */ 334 | 335 | /* Begin PBXNativeTarget section */ 336 | 1772ABB91D188BA0007DC99F /* Model */ = { 337 | isa = PBXNativeTarget; 338 | buildConfigurationList = 1772ABC21D188BA0007DC99F /* Build configuration list for PBXNativeTarget "Model" */; 339 | buildPhases = ( 340 | 1772ABB51D188BA0007DC99F /* Sources */, 341 | 1772ABB61D188BA0007DC99F /* Frameworks */, 342 | 1772ABB71D188BA0007DC99F /* Headers */, 343 | 1772ABB81D188BA0007DC99F /* Resources */, 344 | ); 345 | buildRules = ( 346 | ); 347 | dependencies = ( 348 | ); 349 | name = Model; 350 | productName = Mensa; 351 | productReference = 1772ABBA1D188BA0007DC99F /* Mensa.framework */; 352 | productType = "com.apple.product-type.framework"; 353 | }; 354 | 17DFC9EF225E7E9C00871C7D /* Controller */ = { 355 | isa = PBXNativeTarget; 356 | buildConfigurationList = 17DFC9F5225E7E9C00871C7D /* Build configuration list for PBXNativeTarget "Controller" */; 357 | buildPhases = ( 358 | 17DFC9EB225E7E9C00871C7D /* Headers */, 359 | 17DFC9EC225E7E9C00871C7D /* Sources */, 360 | 17DFC9ED225E7E9C00871C7D /* Frameworks */, 361 | 17DFC9EE225E7E9C00871C7D /* Resources */, 362 | ); 363 | buildRules = ( 364 | ); 365 | dependencies = ( 366 | ); 367 | name = Controller; 368 | productName = Controller; 369 | productReference = 17DFC9F0225E7E9C00871C7D /* Mensa.framework */; 370 | productType = "com.apple.product-type.framework"; 371 | }; 372 | 17F803042255940300212525 /* View */ = { 373 | isa = PBXNativeTarget; 374 | buildConfigurationList = 17F8030A2255940300212525 /* Build configuration list for PBXNativeTarget "View" */; 375 | buildPhases = ( 376 | 17F803002255940300212525 /* Headers */, 377 | 17F803012255940300212525 /* Sources */, 378 | 17F803022255940300212525 /* Frameworks */, 379 | 17F803032255940300212525 /* Resources */, 380 | ); 381 | buildRules = ( 382 | ); 383 | dependencies = ( 384 | ); 385 | name = View; 386 | productName = View; 387 | productReference = 17F803052255940300212525 /* Mensa.framework */; 388 | productType = "com.apple.product-type.framework"; 389 | }; 390 | /* End PBXNativeTarget section */ 391 | 392 | /* Begin PBXProject section */ 393 | 1772ABB11D188BA0007DC99F /* Project object */ = { 394 | isa = PBXProject; 395 | attributes = { 396 | LastSwiftUpdateCheck = 0800; 397 | LastUpgradeCheck = 1020; 398 | ORGANIZATIONNAME = CultivR; 399 | TargetAttributes = { 400 | 1772ABB91D188BA0007DC99F = { 401 | CreatedOnToolsVersion = 8.0; 402 | DevelopmentTeamName = "Jordan Kay (Personal Team)"; 403 | LastSwiftMigration = 1020; 404 | ProvisioningStyle = Automatic; 405 | }; 406 | 17DFC9EF225E7E9C00871C7D = { 407 | CreatedOnToolsVersion = 10.2; 408 | DevelopmentTeam = CVQ97C93T5; 409 | ProvisioningStyle = Automatic; 410 | }; 411 | 17F803042255940300212525 = { 412 | CreatedOnToolsVersion = 10.2; 413 | DevelopmentTeam = CVQ97C93T5; 414 | ProvisioningStyle = Automatic; 415 | }; 416 | }; 417 | }; 418 | buildConfigurationList = 1772ABB41D188BA0007DC99F /* Build configuration list for PBXProject "Mensa" */; 419 | compatibilityVersion = "Xcode 3.2"; 420 | developmentRegion = en; 421 | hasScannedForEncodings = 0; 422 | knownRegions = ( 423 | en, 424 | Base, 425 | ); 426 | mainGroup = 1772ABB01D188BA0007DC99F; 427 | productRefGroup = 1772ABBB1D188BA0007DC99F /* Products */; 428 | projectDirPath = ""; 429 | projectRoot = ""; 430 | targets = ( 431 | 1772ABB91D188BA0007DC99F /* Model */, 432 | 17F803042255940300212525 /* View */, 433 | 17DFC9EF225E7E9C00871C7D /* Controller */, 434 | ); 435 | }; 436 | /* End PBXProject section */ 437 | 438 | /* Begin PBXResourcesBuildPhase section */ 439 | 1772ABB81D188BA0007DC99F /* Resources */ = { 440 | isa = PBXResourcesBuildPhase; 441 | buildActionMask = 2147483647; 442 | files = ( 443 | ); 444 | runOnlyForDeploymentPostprocessing = 0; 445 | }; 446 | 17DFC9EE225E7E9C00871C7D /* Resources */ = { 447 | isa = PBXResourcesBuildPhase; 448 | buildActionMask = 2147483647; 449 | files = ( 450 | ); 451 | runOnlyForDeploymentPostprocessing = 0; 452 | }; 453 | 17F803032255940300212525 /* Resources */ = { 454 | isa = PBXResourcesBuildPhase; 455 | buildActionMask = 2147483647; 456 | files = ( 457 | ); 458 | runOnlyForDeploymentPostprocessing = 0; 459 | }; 460 | /* End PBXResourcesBuildPhase section */ 461 | 462 | /* Begin PBXSourcesBuildPhase section */ 463 | 1772ABB51D188BA0007DC99F /* Sources */ = { 464 | isa = PBXSourcesBuildPhase; 465 | buildActionMask = 2147483647; 466 | files = ( 467 | 17DFC9E4225E6D4200871C7D /* Section.swift in Sources */, 468 | 17DFCA5C22669F7900871C7D /* SectionIndexPath.swift in Sources */, 469 | 172766182255983600C11D4A /* DataSource.swift in Sources */, 470 | 17718F0C22A857F2004351DE /* MutableSingleSectionDataSource.swift in Sources */, 471 | 17700131228B1BDB006EB3FD /* ItemPosition.swift in Sources */, 472 | 17DFC9E6225E6D8200871C7D /* SingleSectionDataSource.swift in Sources */, 473 | 17DFCA5A2266958800871C7D /* Model.swift in Sources */, 474 | 17718F0822A855E9004351DE /* MutableDataSource.swift in Sources */, 475 | ); 476 | runOnlyForDeploymentPostprocessing = 0; 477 | }; 478 | 17DFC9EC225E7E9C00871C7D /* Sources */ = { 479 | isa = PBXSourcesBuildPhase; 480 | buildActionMask = 2147483647; 481 | files = ( 482 | 17F29F1222825CFC009F5121 /* HostingCollectionViewCell.swift in Sources */, 483 | 17F6A92B2266A3C100CBC866 /* HostingView.swift in Sources */, 484 | 17718EFD22A834BE004351DE /* ScrollEvent.swift in Sources */, 485 | 176A254F226E967A0064488F /* ItemTypeVariantIdentifier.swift in Sources */, 486 | 176A2549226E93100064488F /* Identifier.swift in Sources */, 487 | 17F29F0D22825CF0009F5121 /* HostingCollectionView.swift in Sources */, 488 | 17DFCA06225EA9FA00871C7D /* ItemDisplaying.swift in Sources */, 489 | 17DFCA2D225EDA8900871C7D /* DataMediator.swift in Sources */, 490 | 17F6A92C2266A3C100CBC866 /* HostingTableView.swift in Sources */, 491 | 17D4F2362283720D00FDD335 /* DataDisplayContext.swift in Sources */, 492 | 17700133228B1CA5006EB3FD /* ItemPosition.swift in Sources */, 493 | 17D4F2812285E8F200FDD335 /* ReusableView.swift in Sources */, 494 | 17D4F27B2285E38700FDD335 /* HostingHeaderFooterView.swift in Sources */, 495 | 17DFC9FB225E7F3600871C7D /* DataSource.swift in Sources */, 496 | 17DFCA392260272200871C7D /* ItemMediator.swift in Sources */, 497 | 176A254A226E93100064488F /* ItemTypeIdentifier.swift in Sources */, 498 | 17DFCA1F225ECEA100871C7D /* DataDisplaying.swift in Sources */, 499 | 17DFC9F8225E7F2E00871C7D /* Controller.swift in Sources */, 500 | 17718F0D22A857F2004351DE /* MutableSingleSectionDataSource.swift in Sources */, 501 | 17DFCA5D22669FB400871C7D /* SectionIndexPath.swift in Sources */, 502 | 17D4F27E2285E39500FDD335 /* HostingSupplementaryView.swift in Sources */, 503 | 17F6A92D2266A3C100CBC866 /* HostingTableViewCell.swift in Sources */, 504 | 17DFCA442261166100871C7D /* DataInterfacing.swift in Sources */, 505 | 17DFC9FC225E7F3600871C7D /* SingleSectionDataSource.swift in Sources */, 506 | 17718F0A22A8563C004351DE /* MutableDataSource.swift in Sources */, 507 | 17DFC9FA225E7F3600871C7D /* Section.swift in Sources */, 508 | 17718F6522AB2685004351DE /* HostingStrategy.swift in Sources */, 509 | 17DFCA05225EA9B100871C7D /* ItemInterfacing.swift in Sources */, 510 | ); 511 | runOnlyForDeploymentPostprocessing = 0; 512 | }; 513 | 17F803012255940300212525 /* Sources */ = { 514 | isa = PBXSourcesBuildPhase; 515 | buildActionMask = 2147483647; 516 | files = ( 517 | 17F29F0E22825CF1009F5121 /* HostingCollectionView.swift in Sources */, 518 | 17F6A92A2266A3C000CBC866 /* HostingTableViewCell.swift in Sources */, 519 | 17D4F27A2285E38700FDD335 /* HostingHeaderFooterView.swift in Sources */, 520 | 17D4F2802285E8F200FDD335 /* ReusableView.swift in Sources */, 521 | 17DFCA1D225ECE3A00871C7D /* DataDisplaying.swift in Sources */, 522 | 17718F6422AB2685004351DE /* HostingStrategy.swift in Sources */, 523 | 17DFCA02225EA56A00871C7D /* ItemDisplaying.swift in Sources */, 524 | 17D4F27D2285E39500FDD335 /* HostingSupplementaryView.swift in Sources */, 525 | 17718EFC22A834B3004351DE /* ScrollEvent.swift in Sources */, 526 | 17F6A9282266A3C000CBC866 /* HostingView.swift in Sources */, 527 | 17D4F2352283720D00FDD335 /* DataDisplayContext.swift in Sources */, 528 | 17F29F1122825CFC009F5121 /* HostingCollectionViewCell.swift in Sources */, 529 | 17700132228B1C99006EB3FD /* ItemPosition.swift in Sources */, 530 | 17F6A9292266A3C000CBC866 /* HostingTableView.swift in Sources */, 531 | 17F80310225594A300212525 /* View.swift in Sources */, 532 | ); 533 | runOnlyForDeploymentPostprocessing = 0; 534 | }; 535 | /* End PBXSourcesBuildPhase section */ 536 | 537 | /* Begin XCBuildConfiguration section */ 538 | 1772ABC01D188BA0007DC99F /* Debug */ = { 539 | isa = XCBuildConfiguration; 540 | buildSettings = { 541 | ALWAYS_SEARCH_USER_PATHS = NO; 542 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 543 | CLANG_ANALYZER_NONNULL = YES; 544 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 545 | CLANG_CXX_LIBRARY = "libc++"; 546 | CLANG_ENABLE_MODULES = YES; 547 | CLANG_ENABLE_OBJC_ARC = YES; 548 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 549 | CLANG_WARN_BOOL_CONVERSION = YES; 550 | CLANG_WARN_COMMA = YES; 551 | CLANG_WARN_CONSTANT_CONVERSION = YES; 552 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 553 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 554 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 555 | CLANG_WARN_EMPTY_BODY = YES; 556 | CLANG_WARN_ENUM_CONVERSION = YES; 557 | CLANG_WARN_INFINITE_RECURSION = YES; 558 | CLANG_WARN_INT_CONVERSION = YES; 559 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 560 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 561 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 562 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 563 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 564 | CLANG_WARN_STRICT_PROTOTYPES = YES; 565 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 566 | CLANG_WARN_UNREACHABLE_CODE = YES; 567 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 568 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 569 | COPY_PHASE_STRIP = NO; 570 | CURRENT_PROJECT_VERSION = 1; 571 | DEBUG_INFORMATION_FORMAT = dwarf; 572 | ENABLE_STRICT_OBJC_MSGSEND = YES; 573 | ENABLE_TESTABILITY = YES; 574 | GCC_C_LANGUAGE_STANDARD = gnu99; 575 | GCC_DYNAMIC_NO_PIC = NO; 576 | GCC_NO_COMMON_BLOCKS = YES; 577 | GCC_OPTIMIZATION_LEVEL = 0; 578 | GCC_PREPROCESSOR_DEFINITIONS = ( 579 | "DEBUG=1", 580 | "$(inherited)", 581 | ); 582 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 583 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 584 | GCC_WARN_UNDECLARED_SELECTOR = YES; 585 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 586 | GCC_WARN_UNUSED_FUNCTION = YES; 587 | GCC_WARN_UNUSED_VARIABLE = YES; 588 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 589 | MTL_ENABLE_DEBUG_INFO = YES; 590 | ONLY_ACTIVE_ARCH = YES; 591 | SDKROOT = iphoneos; 592 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 593 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 594 | TARGETED_DEVICE_FAMILY = "1,2"; 595 | VERSIONING_SYSTEM = "apple-generic"; 596 | VERSION_INFO_PREFIX = ""; 597 | }; 598 | name = Debug; 599 | }; 600 | 1772ABC11D188BA0007DC99F /* Release */ = { 601 | isa = XCBuildConfiguration; 602 | buildSettings = { 603 | ALWAYS_SEARCH_USER_PATHS = NO; 604 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 605 | CLANG_ANALYZER_NONNULL = YES; 606 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 607 | CLANG_CXX_LIBRARY = "libc++"; 608 | CLANG_ENABLE_MODULES = YES; 609 | CLANG_ENABLE_OBJC_ARC = YES; 610 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 611 | CLANG_WARN_BOOL_CONVERSION = YES; 612 | CLANG_WARN_COMMA = YES; 613 | CLANG_WARN_CONSTANT_CONVERSION = YES; 614 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 615 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 616 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 617 | CLANG_WARN_EMPTY_BODY = YES; 618 | CLANG_WARN_ENUM_CONVERSION = YES; 619 | CLANG_WARN_INFINITE_RECURSION = YES; 620 | CLANG_WARN_INT_CONVERSION = YES; 621 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 622 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 623 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 624 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 625 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 626 | CLANG_WARN_STRICT_PROTOTYPES = YES; 627 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 628 | CLANG_WARN_UNREACHABLE_CODE = YES; 629 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 630 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 631 | COPY_PHASE_STRIP = NO; 632 | CURRENT_PROJECT_VERSION = 1; 633 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 634 | ENABLE_NS_ASSERTIONS = NO; 635 | ENABLE_STRICT_OBJC_MSGSEND = YES; 636 | GCC_C_LANGUAGE_STANDARD = gnu99; 637 | GCC_NO_COMMON_BLOCKS = YES; 638 | GCC_OPTIMIZATION_LEVEL = fast; 639 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 640 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 641 | GCC_WARN_UNDECLARED_SELECTOR = YES; 642 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 643 | GCC_WARN_UNUSED_FUNCTION = YES; 644 | GCC_WARN_UNUSED_VARIABLE = YES; 645 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 646 | MTL_ENABLE_DEBUG_INFO = NO; 647 | SDKROOT = iphoneos; 648 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 649 | TARGETED_DEVICE_FAMILY = "1,2"; 650 | VALIDATE_PRODUCT = YES; 651 | VERSIONING_SYSTEM = "apple-generic"; 652 | VERSION_INFO_PREFIX = ""; 653 | }; 654 | name = Release; 655 | }; 656 | 1772ABC31D188BA0007DC99F /* Debug */ = { 657 | isa = XCBuildConfiguration; 658 | buildSettings = { 659 | CLANG_ENABLE_MODULES = YES; 660 | CODE_SIGN_IDENTITY = ""; 661 | DEFINES_MODULE = YES; 662 | DEVELOPMENT_TEAM = ""; 663 | DYLIB_COMPATIBILITY_VERSION = 1; 664 | DYLIB_CURRENT_VERSION = 1; 665 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 666 | ENABLE_BITCODE = NO; 667 | INFOPLIST_FILE = Mensa/Resources/Info.plist; 668 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 669 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 670 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 671 | PRODUCT_BUNDLE_IDENTIFIER = co.cultivr.Mensa; 672 | PRODUCT_NAME = Mensa; 673 | SKIP_INSTALL = YES; 674 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 675 | SWIFT_VERSION = 5.0; 676 | }; 677 | name = Debug; 678 | }; 679 | 1772ABC41D188BA0007DC99F /* Release */ = { 680 | isa = XCBuildConfiguration; 681 | buildSettings = { 682 | CLANG_ENABLE_MODULES = YES; 683 | CODE_SIGN_IDENTITY = ""; 684 | DEFINES_MODULE = YES; 685 | DEVELOPMENT_TEAM = ""; 686 | DYLIB_COMPATIBILITY_VERSION = 1; 687 | DYLIB_CURRENT_VERSION = 1; 688 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 689 | ENABLE_BITCODE = NO; 690 | INFOPLIST_FILE = Mensa/Resources/Info.plist; 691 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 692 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 693 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 694 | PRODUCT_BUNDLE_IDENTIFIER = co.cultivr.Mensa; 695 | PRODUCT_NAME = Mensa; 696 | SKIP_INSTALL = YES; 697 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 698 | SWIFT_VERSION = 5.0; 699 | }; 700 | name = Release; 701 | }; 702 | 17DFC9F6225E7E9C00871C7D /* Debug */ = { 703 | isa = XCBuildConfiguration; 704 | buildSettings = { 705 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 706 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 707 | CLANG_ENABLE_OBJC_WEAK = YES; 708 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 709 | CODE_SIGN_IDENTITY = "iPhone Developer"; 710 | CODE_SIGN_STYLE = Automatic; 711 | DEFINES_MODULE = YES; 712 | DEVELOPMENT_TEAM = CVQ97C93T5; 713 | DYLIB_COMPATIBILITY_VERSION = 1; 714 | DYLIB_CURRENT_VERSION = 1; 715 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 716 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; 717 | GCC_C_LANGUAGE_STANDARD = gnu11; 718 | INFOPLIST_FILE = "$(SRCROOT)/Mensa/Resources/Info.plist"; 719 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 720 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 721 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 722 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 723 | MTL_FAST_MATH = YES; 724 | PRODUCT_BUNDLE_IDENTIFIER = co.cultivr.Mensa; 725 | PRODUCT_NAME = Mensa; 726 | SKIP_INSTALL = YES; 727 | SWIFT_VERSION = 5.0; 728 | TARGETED_DEVICE_FAMILY = "1,2"; 729 | }; 730 | name = Debug; 731 | }; 732 | 17DFC9F7225E7E9C00871C7D /* Release */ = { 733 | isa = XCBuildConfiguration; 734 | buildSettings = { 735 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 736 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 737 | CLANG_ENABLE_OBJC_WEAK = YES; 738 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 739 | CODE_SIGN_IDENTITY = "iPhone Developer"; 740 | CODE_SIGN_STYLE = Automatic; 741 | DEFINES_MODULE = YES; 742 | DEVELOPMENT_TEAM = CVQ97C93T5; 743 | DYLIB_COMPATIBILITY_VERSION = 1; 744 | DYLIB_CURRENT_VERSION = 1; 745 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 746 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; 747 | GCC_C_LANGUAGE_STANDARD = gnu11; 748 | INFOPLIST_FILE = "$(SRCROOT)/Mensa/Resources/Info.plist"; 749 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 750 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 751 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 752 | MTL_FAST_MATH = YES; 753 | PRODUCT_BUNDLE_IDENTIFIER = co.cultivr.Mensa; 754 | PRODUCT_NAME = Mensa; 755 | SKIP_INSTALL = YES; 756 | SWIFT_VERSION = 5.0; 757 | TARGETED_DEVICE_FAMILY = "1,2"; 758 | }; 759 | name = Release; 760 | }; 761 | 17F8030B2255940300212525 /* Debug */ = { 762 | isa = XCBuildConfiguration; 763 | buildSettings = { 764 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 765 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 766 | CLANG_ENABLE_OBJC_WEAK = YES; 767 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 768 | CODE_SIGN_IDENTITY = "iPhone Developer"; 769 | CODE_SIGN_STYLE = Automatic; 770 | DEFINES_MODULE = YES; 771 | DEVELOPMENT_TEAM = CVQ97C93T5; 772 | DYLIB_COMPATIBILITY_VERSION = 1; 773 | DYLIB_CURRENT_VERSION = 1; 774 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 775 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; 776 | GCC_C_LANGUAGE_STANDARD = gnu11; 777 | INFOPLIST_FILE = "$(SRCROOT)/Mensa/Resources/Info.plist"; 778 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 779 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 780 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 781 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 782 | MTL_FAST_MATH = YES; 783 | PRODUCT_BUNDLE_IDENTIFIER = co.cultivr.Mensa; 784 | PRODUCT_NAME = Mensa; 785 | SKIP_INSTALL = YES; 786 | SWIFT_VERSION = 5.0; 787 | TARGETED_DEVICE_FAMILY = "1,2"; 788 | }; 789 | name = Debug; 790 | }; 791 | 17F8030C2255940300212525 /* Release */ = { 792 | isa = XCBuildConfiguration; 793 | buildSettings = { 794 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 795 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 796 | CLANG_ENABLE_OBJC_WEAK = YES; 797 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 798 | CODE_SIGN_IDENTITY = "iPhone Developer"; 799 | CODE_SIGN_STYLE = Automatic; 800 | DEFINES_MODULE = YES; 801 | DEVELOPMENT_TEAM = CVQ97C93T5; 802 | DYLIB_COMPATIBILITY_VERSION = 1; 803 | DYLIB_CURRENT_VERSION = 1; 804 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 805 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; 806 | GCC_C_LANGUAGE_STANDARD = gnu11; 807 | INFOPLIST_FILE = "$(SRCROOT)/Mensa/Resources/Info.plist"; 808 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 809 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 810 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 811 | MTL_FAST_MATH = YES; 812 | PRODUCT_BUNDLE_IDENTIFIER = co.cultivr.Mensa; 813 | PRODUCT_NAME = Mensa; 814 | SKIP_INSTALL = YES; 815 | SWIFT_VERSION = 5.0; 816 | TARGETED_DEVICE_FAMILY = "1,2"; 817 | }; 818 | name = Release; 819 | }; 820 | /* End XCBuildConfiguration section */ 821 | 822 | /* Begin XCConfigurationList section */ 823 | 1772ABB41D188BA0007DC99F /* Build configuration list for PBXProject "Mensa" */ = { 824 | isa = XCConfigurationList; 825 | buildConfigurations = ( 826 | 1772ABC01D188BA0007DC99F /* Debug */, 827 | 1772ABC11D188BA0007DC99F /* Release */, 828 | ); 829 | defaultConfigurationIsVisible = 0; 830 | defaultConfigurationName = Release; 831 | }; 832 | 1772ABC21D188BA0007DC99F /* Build configuration list for PBXNativeTarget "Model" */ = { 833 | isa = XCConfigurationList; 834 | buildConfigurations = ( 835 | 1772ABC31D188BA0007DC99F /* Debug */, 836 | 1772ABC41D188BA0007DC99F /* Release */, 837 | ); 838 | defaultConfigurationIsVisible = 0; 839 | defaultConfigurationName = Release; 840 | }; 841 | 17DFC9F5225E7E9C00871C7D /* Build configuration list for PBXNativeTarget "Controller" */ = { 842 | isa = XCConfigurationList; 843 | buildConfigurations = ( 844 | 17DFC9F6225E7E9C00871C7D /* Debug */, 845 | 17DFC9F7225E7E9C00871C7D /* Release */, 846 | ); 847 | defaultConfigurationIsVisible = 0; 848 | defaultConfigurationName = Release; 849 | }; 850 | 17F8030A2255940300212525 /* Build configuration list for PBXNativeTarget "View" */ = { 851 | isa = XCConfigurationList; 852 | buildConfigurations = ( 853 | 17F8030B2255940300212525 /* Debug */, 854 | 17F8030C2255940300212525 /* Release */, 855 | ); 856 | defaultConfigurationIsVisible = 0; 857 | defaultConfigurationName = Release; 858 | }; 859 | /* End XCConfigurationList section */ 860 | }; 861 | rootObject = 1772ABB11D188BA0007DC99F /* Project object */; 862 | } 863 | --------------------------------------------------------------------------------