├── .gitignore ├── Classes ├── AppDelegate.swift └── UI │ ├── BaseMagazineLayout │ ├── BaseMagazineLayoutVC.swift │ ├── CellConfigurators.swift │ ├── CellsRegistrator │ │ └── CollectionViewCellsRegistrator.swift │ ├── Data │ │ └── MagazineLayoutSection.swift │ ├── Protocols │ │ └── StepSupportable.swift │ └── Screen │ │ └── Screen.swift │ ├── DesignSystem │ ├── Cards │ │ ├── CardDestination │ │ │ ├── CardDestination.swift │ │ │ └── CardDestinationVM.swift │ │ └── CardPhotoThumbnail │ │ │ ├── CardPhotoThumbnail.swift │ │ │ └── CardPhotoThumbnailVM.swift │ ├── Colors │ │ └── UIColor+Styles.swift │ ├── Headers │ │ ├── Destination │ │ │ ├── HeaderDestination.swift │ │ │ └── HeaderDestination.xib │ │ ├── Headline2 │ │ │ ├── HeaderHeadline2.swift │ │ │ └── HeaderHeadline2VM.swift │ │ └── SectionTitle │ │ │ ├── HeaderSectionTitle.swift │ │ │ └── HeaderSectionTitleVM.swift │ ├── Rows │ │ ├── RowCaption │ │ │ ├── RowCaption.swift │ │ │ └── RowCaptionVM.swift │ │ ├── RowDestinationTitle │ │ │ ├── RowDestinationTitle.swift │ │ │ ├── RowDestinationTitle.xib │ │ │ └── RowDestinationTitleVM.swift │ │ ├── RowFlightInfo │ │ │ ├── RowFlightInfo.swift │ │ │ ├── RowFlightInfo.xib │ │ │ └── RowFlightInfoVM.swift │ │ ├── RowHeadline1 │ │ │ ├── RowHeadline1.swift │ │ │ └── RowHeadline1VM.swift │ │ ├── RowHorizontalCardsCollection │ │ │ ├── CardsHorizontalRow.swift │ │ │ └── CardsHorizontalRowVM.swift │ │ └── RowText │ │ │ ├── RowText.swift │ │ │ └── RowTextVM.swift │ └── Typography │ │ └── Typography.swift │ ├── Explore │ └── ExploreVM.swift │ ├── Flow │ ├── AppFlow.swift │ ├── ExploreFlow.swift │ └── FlowStep.swift │ ├── Page │ ├── DestinationVC.swift │ └── DestinationVM.swift │ └── Utils │ ├── Reusable.swift │ └── RxUtils.swift ├── Demo └── mockup.gif ├── DesignSystemExample.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── DesignSystemExample.xcscheme ├── Info.plist ├── Podfile ├── Podfile.lock ├── README.md └── Resources ├── Assets └── Icons.xcassets │ ├── AppIcon.appiconset │ ├── Contents.json │ ├── icon-ios-1024@1x.png │ ├── icon-ios-20@2x.png │ ├── icon-ios-20@3x.png │ ├── icon-ios-29@2x.png │ ├── icon-ios-29@3x.png │ ├── icon-ios-40@2x.png │ ├── icon-ios-40@3x.png │ ├── icon-ios-60@2x.png │ └── icon-ios-60@3x.png │ ├── Contents.json │ ├── destination.imageset │ ├── Contents.json │ └── destination.jpg │ ├── header_corner.imageset │ ├── Contents.json │ └── header_corner.pdf │ ├── ico_flight_status.imageset │ ├── Contents.json │ └── ico_flight_status.pdf │ ├── ico_heart.imageset │ ├── Contents.json │ └── ico_heart.pdf │ ├── ico_heart_filled.imageset │ ├── Contents.json │ └── ico_heart_filled.pdf │ ├── ico_left_arrow.imageset │ ├── Contents.json │ └── ico_left_arrow.pdf │ ├── ico_plane.imageset │ ├── Contents.json │ └── ico_plane.pdf │ ├── ico_share.imageset │ ├── Contents.json │ └── ico_share.pdf │ └── ico_star.imageset │ ├── Contents.json │ └── ico_star.pdf ├── Localization └── Localizable.strings └── StoryBoards ├── LaunchScreen.storyboard └── Main.storyboard /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | *.xcworkspace 24 | .DS_Store 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | .idea 69 | FailureDiffs/ 70 | *.mobileprovision 71 | *.cer 72 | fastlane/README.md 73 | -------------------------------------------------------------------------------- /Classes/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Spendo 4 | // 5 | // Created by Igors Nemenonoks on 10/05/2019. 6 | // Copyright © 2019 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RxFlow 11 | import RxSwift 12 | 13 | @UIApplicationMain 14 | class AppDelegate: UIResponder, UIApplicationDelegate { 15 | 16 | var window: UIWindow? 17 | let coordinator = FlowCoordinator() 18 | let bag = DisposeBag() 19 | 20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 21 | guard let window = self.window else { return false } 22 | 23 | Typography.registerAllStyles() 24 | let appFlow = AppFlow(withWindow: window) 25 | 26 | self.coordinator.coordinate(flow: appFlow, with: AppStepper()) 27 | 28 | return true 29 | } 30 | 31 | func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { 32 | // 33 | } 34 | 35 | func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { 36 | // 37 | } 38 | 39 | func applicationWillResignActive(_ application: UIApplication) { 40 | // 41 | } 42 | 43 | func applicationDidEnterBackground(_ application: UIApplication) { 44 | // 45 | } 46 | 47 | func applicationWillEnterForeground(_ application: UIApplication) { 48 | // 49 | } 50 | 51 | func applicationDidBecomeActive(_ application: UIApplication) { 52 | // 53 | } 54 | 55 | func applicationWillTerminate(_ application: UIApplication) { 56 | // 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Classes/UI/BaseMagazineLayout/BaseMagazineLayoutVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseMagazineLayoutVC.swift 3 | // Chili Labs 4 | // 5 | // Created by Igors Nemenonoks on 11/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | import RxSwift 12 | import RxCocoa 13 | import SnapKit 14 | 15 | protocol PBaseMagazineLayoutVC: UICollectionViewDelegateMagazineLayout, UICollectionViewDataSource { 16 | var sections: Binder<[MagazineLayoutSection]> { get } 17 | var collectionView: UICollectionView { get } 18 | func didSelectItem() -> Observable> 19 | } 20 | 21 | class BaseMagazineLayoutVC: UIViewController, PBaseMagazineLayoutVC { 22 | 23 | var sections: Binder<[MagazineLayoutSection]> { 24 | return Binder(self) { vc, items in 25 | vc._sections.accept(items) 26 | } 27 | } 28 | 29 | fileprivate let _sections = BehaviorRelay(value: [MagazineLayoutSection]()) 30 | 31 | //published when cell got selected 32 | private let selectPublisher = PublishRelay() 33 | private lazy var cellsRegistrator = CollectionViewCellsRegistrator(collectionView: self.collectionView) 34 | 35 | private let bag = DisposeBag() 36 | 37 | // Collection view 38 | lazy var collectionView: UICollectionView = { 39 | let layout = MagazineLayout() 40 | let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) 41 | collectionView.dataSource = self 42 | collectionView.delegate = self 43 | collectionView.backgroundColor = .white 44 | collectionView.contentInsetAdjustmentBehavior = .always 45 | return collectionView 46 | }() 47 | 48 | override func viewDidLoad() { 49 | super.viewDidLoad() 50 | 51 | self.view.backgroundColor = .white 52 | self.view.insertSubview(self.collectionView, at: 0) 53 | 54 | self.collectionView.translatesAutoresizingMaskIntoConstraints = false 55 | self.collectionView.snp.makeConstraints { $0.edges.equalTo(0) } 56 | 57 | self._sections.subscribe(onNext: { [weak self] sections in 58 | self?.cellsRegistrator.registerCells(for: sections) 59 | }).disposed(by: bag) 60 | } 61 | 62 | func didSelectItem() -> Observable> { 63 | return self.selectPublisher 64 | .filter({ (configurator) -> Bool in 65 | return configurator is MagazineCellConfigurator 66 | }) 67 | .map { configurator -> MagazineCellConfigurator in 68 | return configurator as! MagazineCellConfigurator 69 | } 70 | } 71 | } 72 | 73 | extension BaseMagazineLayoutVC: UICollectionViewDelegateMagazineLayout { 74 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeModeForItemAt indexPath: IndexPath) -> MagazineLayoutItemSizeMode { 75 | return self._sections.value[indexPath.section].items[indexPath.row].sizeMode 76 | } 77 | 78 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForHeaderInSectionAtIndex index: Int) -> MagazineLayoutHeaderVisibilityMode { 79 | return self._sections.value[index].header.visibilityMode 80 | } 81 | 82 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForFooterInSectionAtIndex index: Int) -> MagazineLayoutFooterVisibilityMode { 83 | return self._sections.value[index].footer.visibilityMode 84 | } 85 | // swiftlint:disable line_length 86 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForBackgroundInSectionAtIndex index: Int) -> MagazineLayoutBackgroundVisibilityMode { 87 | return self._sections.value[index].background.visibilityMode 88 | } 89 | 90 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, horizontalSpacingForItemsInSectionAtIndex index: Int) -> CGFloat { 91 | return self._sections.value[index].itemsInset.right 92 | } 93 | 94 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, verticalSpacingForElementsInSectionAtIndex index: Int) -> CGFloat { 95 | return self._sections.value[index].itemsInset.bottom 96 | } 97 | 98 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForSectionAtIndex index: Int) -> UIEdgeInsets { 99 | return self._sections.value[index].sectionInset 100 | } 101 | 102 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForItemsInSectionAtIndex index: Int) -> UIEdgeInsets { 103 | return self._sections.value[index].itemsInset 104 | } 105 | } 106 | extension BaseMagazineLayoutVC: UICollectionViewDataSource { 107 | 108 | func numberOfSections(in collectionView: UICollectionView) -> Int { 109 | return self._sections.value.count 110 | } 111 | 112 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 113 | return self._sections.value[section].items.count 114 | } 115 | 116 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 117 | let cellConfigurator = self._sections.value[indexPath.section].items[indexPath.row] 118 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: type(of: cellConfigurator).cellReuseIdentifier, for: indexPath) 119 | cellConfigurator.configure(cell: cell) 120 | return cell 121 | } 122 | 123 | func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { 124 | 125 | let section = _sections.value[indexPath.section] 126 | if let sectionItem = section.header.item, kind == MagazineLayout.SupplementaryViewKind.sectionHeader { 127 | let cell = collectionView.dequeueReusableSupplementaryView(ofKind: MagazineLayout.SupplementaryViewKind.sectionHeader, 128 | withReuseIdentifier: type(of: sectionItem).cellReuseIdentifier, 129 | for: indexPath) 130 | sectionItem.configure(cell: cell) 131 | return cell 132 | } else if let sectionItem = section.footer.item, kind == MagazineLayout.SupplementaryViewKind.sectionFooter { 133 | let cell = collectionView.dequeueReusableSupplementaryView(ofKind: MagazineLayout.SupplementaryViewKind.sectionFooter, 134 | withReuseIdentifier: type(of: sectionItem).cellReuseIdentifier, 135 | for: indexPath) 136 | sectionItem.configure(cell: cell) 137 | return cell 138 | } 139 | 140 | fatalError("Not supported") 141 | } 142 | 143 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 144 | self.selectPublisher.accept(self._sections.value[indexPath.section].items[indexPath.row]) 145 | self._sections.value[indexPath.section].items[indexPath.row].didSelect() 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Classes/UI/BaseMagazineLayout/CellConfigurators.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CellConfigurators.swift 3 | // Spendo 4 | // 5 | // Created by Igors Nemenonoks on 15/05/2019. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | 12 | //Cell configurators 13 | 14 | protocol Diffable { 15 | var diffHash: Int { get } 16 | } 17 | 18 | protocol CellSizable: GenericCell { 19 | var sizeMode: MagazineLayoutItemSizeMode { get } 20 | } 21 | 22 | //means that cell can be selected 23 | protocol SelectableData { 24 | func didSelect() 25 | } 26 | 27 | protocol GenericCell { } 28 | 29 | protocol CellConfigurator: CellSizable, Diffable, SelectableData { 30 | static var cellType: GenericCell.Type { get } 31 | static var cellReuseIdentifier: String { get } 32 | 33 | func configure(cell: UIView) 34 | func didSelect() 35 | } 36 | 37 | protocol ConfigurableCell: GenericCell, Reusable { 38 | associatedtype DataType 39 | func configure(item: DataType) 40 | } 41 | 42 | //defines that object should return its configurator 43 | protocol CellConfigurable { 44 | func configurator() -> CellConfigurator 45 | } 46 | 47 | typealias MagazineCellDataType = Diffable & CellSizable & SelectableData & CellConfigurable 48 | 49 | final class MagazineCellConfigurator: CellConfigurator where CellType.DataType == DataType, CellType: UIView { 50 | 51 | let item: DataType 52 | 53 | init(item: DataType) { 54 | self.item = item 55 | } 56 | 57 | func configure(cell: UIView) { 58 | (cell as? CellType)?.configure(item: item) 59 | } 60 | 61 | func didSelect() { 62 | item.didSelect() 63 | } 64 | 65 | static var cellReuseIdentifier: String { 66 | return CellType.reuseIdentifier 67 | } 68 | 69 | static var cellType: GenericCell.Type { 70 | return CellType.self 71 | } 72 | 73 | var sizeMode: MagazineLayoutItemSizeMode { 74 | return item.sizeMode 75 | } 76 | 77 | var diffHash: Int { 78 | return String(describing: DataType.self).hashValue ^ self.item.diffHash 79 | } 80 | } 81 | 82 | //Reusable cells like headers or footers 83 | protocol SupplementaryCellSizable: GenericCell { 84 | var heightMode: MagazineLayoutHeaderHeightMode { get } 85 | } 86 | 87 | protocol SupplementaryCellConfigurator: SupplementaryCellSizable, Diffable { 88 | static var cellType: GenericCell.Type { get } 89 | static var cellReuseIdentifier: String { get } 90 | 91 | func configure(cell: UIView) 92 | } 93 | 94 | protocol SupplementaryConfigurable { 95 | func configurator() -> SupplementaryCellConfigurator 96 | } 97 | 98 | typealias MagazineSupplementaryDataType = Diffable & SupplementaryCellSizable & SupplementaryConfigurable 99 | 100 | final class MagazineSupplementaryCellConfigurator: SupplementaryCellConfigurator where CellType.DataType == DataType, CellType: UIView { 101 | 102 | let item: DataType 103 | 104 | init(item: DataType) { 105 | self.item = item 106 | } 107 | 108 | func configure(cell: UIView) { 109 | (cell as? CellType)?.configure(item: item) 110 | } 111 | 112 | static var cellReuseIdentifier: String { 113 | return CellType.reuseIdentifier 114 | } 115 | 116 | static var cellType: GenericCell.Type { 117 | return CellType.self 118 | } 119 | 120 | var heightMode: MagazineLayoutHeaderHeightMode { 121 | return item.heightMode 122 | } 123 | 124 | var diffHash: Int { 125 | return String(describing: DataType.self).hashValue ^ self.item.diffHash 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Classes/UI/BaseMagazineLayout/CellsRegistrator/CollectionViewCellsRegistrator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewCellsRegistrator.swift 3 | // Spendo 4 | // 5 | // Created by Igors Nemenonoks on 17/05/2019. 6 | // Copyright © 2019 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import MagazineLayout 12 | 13 | final class CollectionViewCellsRegistrator { 14 | 15 | private(set) weak var collectionView: UICollectionView? 16 | private var registeredIdentifiers = Set() 17 | 18 | init(collectionView: UICollectionView) { 19 | self.collectionView = collectionView 20 | } 21 | 22 | func registerCells(for sections: [MagazineLayoutSection]) { 23 | sections.forEach({ (section) in 24 | if let headerItem = section.header.item, 25 | registeredIdentifiers.contains(type(of: headerItem).cellReuseIdentifier) == false, 26 | let headerType = type(of: headerItem).cellType as? (UICollectionReusableView & Reusable).Type { 27 | 28 | self.registerReusableCell(type: headerType) 29 | } 30 | self.register(cellConfigs: section.items) 31 | }) 32 | } 33 | 34 | func register(cellConfigs: [CellConfigurator]) { 35 | cellConfigs.forEach({ (conf) in 36 | if let cellType = type(of: conf).cellType as? (UICollectionViewCell & Reusable).Type, 37 | registeredIdentifiers.contains(cellType.reuseIdentifier) == false { 38 | self.registerCell(type: cellType) 39 | } 40 | }) 41 | } 42 | 43 | private func registerReusableCell(type aType: (UICollectionReusableView & Reusable).Type) { 44 | if let nib = aType.nib { 45 | self.collectionView?.register(nib, 46 | forSupplementaryViewOfKind: MagazineLayout.SupplementaryViewKind.sectionHeader, 47 | withReuseIdentifier: aType.reuseIdentifier) 48 | } else { 49 | self.collectionView?.register(aType.self, 50 | forSupplementaryViewOfKind: MagazineLayout.SupplementaryViewKind.sectionHeader, 51 | withReuseIdentifier: aType.reuseIdentifier) 52 | } 53 | self.registeredIdentifiers.insert(aType.reuseIdentifier) 54 | } 55 | 56 | private func registerCell(type aType: (UICollectionViewCell & Reusable).Type) { 57 | if let nib = aType.nib { 58 | self.collectionView?.register(nib, forCellWithReuseIdentifier: aType.reuseIdentifier) 59 | } else { 60 | self.collectionView?.register(aType.self, forCellWithReuseIdentifier: aType.reuseIdentifier) 61 | } 62 | registeredIdentifiers.insert(aType.reuseIdentifier) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Classes/UI/BaseMagazineLayout/Data/MagazineLayoutSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MagazineLayoutSection.swift 3 | // Spendo 4 | // 5 | // Created by Igors Nemenonoks on 14/05/2019. 6 | // Copyright © 2019 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | 12 | struct MagazineLayoutSection { 13 | 14 | struct HeaderInfo { 15 | let item: SupplementaryCellConfigurator? 16 | let visibilityMode: MagazineLayoutHeaderVisibilityMode 17 | 18 | static func hidden() -> HeaderInfo { 19 | return .init(item: nil, visibilityMode: .hidden) 20 | } 21 | } 22 | 23 | struct FooterInfo { 24 | let item: SupplementaryCellConfigurator? 25 | let visibilityMode: MagazineLayoutFooterVisibilityMode 26 | 27 | static func hidden() -> FooterInfo { 28 | return .init(item: nil, visibilityMode: .hidden) 29 | } 30 | } 31 | 32 | struct BackgroundInfo { 33 | let visibilityMode: MagazineLayoutBackgroundVisibilityMode 34 | 35 | static func hidden() -> BackgroundInfo { 36 | return .init(visibilityMode: .hidden) 37 | } 38 | } 39 | 40 | let header: HeaderInfo 41 | let footer: FooterInfo 42 | let items: [CellConfigurator] 43 | let background: BackgroundInfo 44 | let sectionInset: UIEdgeInsets 45 | let itemsInset: UIEdgeInsets 46 | 47 | init(items: [CellConfigurator], 48 | header: HeaderInfo = .hidden(), 49 | footer: FooterInfo = .hidden(), 50 | background: BackgroundInfo = .hidden(), 51 | sectionInset: UIEdgeInsets = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16), 52 | itemsInset: UIEdgeInsets = UIEdgeInsets.zero) { 53 | self.header = header 54 | self.footer = footer 55 | self.items = items 56 | self.background = background 57 | self.sectionInset = sectionInset 58 | self.itemsInset = itemsInset 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Classes/UI/BaseMagazineLayout/Protocols/StepSupportable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StepSupportable.swift 3 | // Spendo 4 | // 5 | // Created by Igors Nemenonoks on 17/05/2019. 6 | // Copyright © 2019 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxFlow 11 | 12 | protocol StepSupportable: Stepper { 13 | var defaultStep: Step { get } 14 | func triggerDefaultStep() 15 | } 16 | 17 | extension StepSupportable { 18 | func triggerDefaultStep() { 19 | self.steps.accept(defaultStep) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Classes/UI/BaseMagazineLayout/Screen/Screen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Screen.swift 3 | // Spendo 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | import RxCocoa 12 | import RxFlow 13 | 14 | protocol SectionedViewModel: Stepper { 15 | var sections: Observable<[MagazineLayoutSection]> { get } 16 | } 17 | 18 | class Screen: BaseMagazineLayoutVC { 19 | let viewModel: SectionedViewModel 20 | private let bag = DisposeBag() 21 | 22 | init(viewModel: SectionedViewModel) { 23 | self.viewModel = viewModel 24 | super.init(nibName: nil, bundle: nil) 25 | } 26 | 27 | required init?(coder aDecoder: NSCoder) { 28 | fatalError("init(coder:) has not been implemented") 29 | } 30 | 31 | override func viewDidLoad() { 32 | super.viewDidLoad() 33 | 34 | self.viewModel.sections.bind(to: self.sections).disposed(by: bag) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Cards/CardDestination/CardDestination.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardDestination.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | import Kingfisher 12 | 13 | typealias CardDestinationConfigurator = MagazineCellConfigurator 14 | final class CardDestination: UICollectionViewCell, ConfigurableCell { 15 | 16 | private let imageView: UIImageView = { 17 | let v = UIImageView() 18 | v.contentMode = .scaleAspectFill 19 | v.layer.cornerRadius = 6 20 | v.clipsToBounds = true 21 | v.backgroundColor = .placeholder 22 | return v 23 | }() 24 | 25 | private let titleLabel: UILabel = { 26 | let l = UILabel(frame: .zero) 27 | l.bonMotStyle = Typography.Headline4 28 | l.textColor = .white 29 | return l 30 | }() 31 | 32 | private let subtitleLabel: UILabel = { 33 | let l = UILabel(frame: .zero) 34 | l.bonMotStyle = Typography.Caption2 35 | l.textColor = .white 36 | return l 37 | }() 38 | 39 | override init(frame: CGRect) { 40 | super.init(frame: frame) 41 | 42 | self.contentView.addSubview(imageView) 43 | imageView.snp.makeConstraints { 44 | $0.edges.equalToSuperview() 45 | } 46 | 47 | self.contentView.addSubview(subtitleLabel) 48 | subtitleLabel.snp.makeConstraints { 49 | $0.leading.trailing.equalToSuperview().inset(16) 50 | $0.bottom.equalToSuperview().inset(16) 51 | } 52 | 53 | self.contentView.addSubview(titleLabel) 54 | titleLabel.snp.makeConstraints { 55 | $0.leading.trailing.equalToSuperview().inset(16) 56 | $0.bottom.equalTo(self.subtitleLabel.snp.top) 57 | } 58 | } 59 | 60 | required init?(coder: NSCoder) { 61 | fatalError("init(coder:) has not been implemented") 62 | } 63 | 64 | func configure(item: CardDestinationVM) { 65 | self.imageView.kf.setImage(with: URL(string: item.imageUrl), 66 | options: [.transition(.fade(0.3))]) 67 | self.titleLabel.styledText = item.title 68 | self.subtitleLabel.styledText = item.subtitle 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Cards/CardDestination/CardDestinationVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardDestinationVM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | class CardDestinationVM: MagazineCellDataType, StepSupportable { 16 | 17 | var sizeMode: MagazineLayoutItemSizeMode { 18 | return MagazineLayoutItemSizeMode(widthMode: .thirdWidth, 19 | heightMode: .static(height: 160)) 20 | } 21 | 22 | let imageUrl: String 23 | let title: String 24 | let subtitle: String 25 | 26 | //StepSupportable 27 | let defaultStep: Step 28 | let steps = PublishRelay() 29 | 30 | init(imageUrl: String, title: String, subtitle: String, step: Step) { 31 | self.imageUrl = imageUrl 32 | self.title = title 33 | self.subtitle = subtitle 34 | self.defaultStep = step 35 | } 36 | 37 | var diffHash: Int { 38 | return imageUrl.hashValue 39 | } 40 | 41 | func configurator() -> CellConfigurator { 42 | return CardDestinationConfigurator(item: self) 43 | } 44 | 45 | func didSelect() { 46 | self.steps.accept(defaultStep) 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Cards/CardPhotoThumbnail/CardPhotoThumbnail.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardPhotoThumbnail.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | 12 | typealias CardPhotoThumbnailConfigurator = MagazineCellConfigurator 13 | final class CardPhotoThumbnail: UICollectionViewCell, ConfigurableCell { 14 | 15 | private let imageView: UIImageView = { 16 | let v = UIImageView() 17 | v.contentMode = .scaleAspectFill 18 | v.layer.cornerRadius = 6 19 | v.clipsToBounds = true 20 | v.backgroundColor = .placeholder 21 | return v 22 | }() 23 | 24 | override init(frame: CGRect) { 25 | super.init(frame: frame) 26 | 27 | self.contentView.addSubview(imageView) 28 | imageView.snp.makeConstraints { 29 | $0.edges.equalToSuperview() 30 | } 31 | } 32 | 33 | required init?(coder: NSCoder) { 34 | fatalError("init(coder:) has not been implemented") 35 | } 36 | 37 | func configure(item: CardPhotoThumbnailVM) { 38 | self.imageView.kf.setImage(with: URL(string: item.url), 39 | options: [.transition(.fade(0.3))]) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Cards/CardPhotoThumbnail/CardPhotoThumbnailVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardPhotoThumbnailVM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | struct CardPhotoThumbnailVM: MagazineCellDataType { 16 | 17 | var sizeMode: MagazineLayoutItemSizeMode { 18 | return MagazineLayoutItemSizeMode(widthMode: .thirdWidth, 19 | heightMode: .static(height: 120)) 20 | } 21 | 22 | let url: String 23 | 24 | init(url: String) { 25 | self.url = url 26 | } 27 | 28 | var diffHash: Int { 29 | return url.hashValue 30 | } 31 | 32 | func configurator() -> CellConfigurator { 33 | return CardPhotoThumbnailConfigurator(item: self) 34 | } 35 | 36 | func didSelect() { 37 | // 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Colors/UIColor+Styles.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Styles.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UIColor { 13 | class var mainText: UIColor { 14 | return UIColor.color(with: "#333333") 15 | } 16 | 17 | class var captionText: UIColor { 18 | return UIColor.color(with: "#888888") 19 | } 20 | 21 | class var placeholder: UIColor { 22 | return UIColor.color(with: "#EFEFEF") 23 | } 24 | 25 | class func color(with hex: String) -> UIColor { 26 | var hexFormatted: String = hex.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased() 27 | 28 | if hexFormatted.hasPrefix("#") { 29 | hexFormatted = String(hexFormatted.dropFirst()) 30 | } 31 | 32 | assert(hexFormatted.count == 6, "Invalid hex code") 33 | 34 | var rgbValue: UInt64 = 0 35 | Scanner(string: hexFormatted).scanHexInt64(&rgbValue) 36 | 37 | return UIColor(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 38 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 39 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0, 40 | alpha: 1) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Headers/Destination/HeaderDestination.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderDestination.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class HeaderDestination: UIView { 12 | static let height: CGFloat = 400 13 | static var minimumHeight: CGFloat { return 100 + UIApplication.shared.statusBarFrame.height } 14 | 15 | @IBOutlet weak var topConstraint: NSLayoutConstraint! 16 | @IBOutlet weak var backButton: UIButton! 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | 21 | self.topConstraint.constant = UIApplication.shared.statusBarFrame.height + 4 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Headers/Destination/HeaderDestination.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Headers/Headline2/HeaderHeadline2.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderHeadline2.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RxSwift 11 | import RxCocoa 12 | 13 | typealias HeaderHeadline2Configurator = MagazineSupplementaryCellConfigurator 14 | 15 | final class HeaderHeadline2: UICollectionReusableView, ConfigurableCell { 16 | 17 | private let textLabel: UILabel = { 18 | let label = UILabel(frame: .zero) 19 | label.bonMotStyle = Typography.Headline2 20 | label.numberOfLines = 0 21 | label.textColor = .mainText 22 | return label 23 | }() 24 | 25 | override init(frame: CGRect) { 26 | super.init(frame: frame) 27 | 28 | self.addSubview(textLabel) 29 | textLabel.snp.makeConstraints { 30 | $0.leading.trailing.equalToSuperview() 31 | $0.top.bottom.equalToSuperview().inset(8) 32 | } 33 | } 34 | 35 | required init?(coder: NSCoder) { 36 | fatalError("init(coder:) has not been implemented") 37 | } 38 | 39 | func configure(item: HeaderHeadline2VM) { 40 | textLabel.styledText = item.title 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Headers/Headline2/HeaderHeadline2VM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderHeadline2VM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | struct HeaderHeadline2VM: MagazineSupplementaryDataType { 16 | 17 | let heightMode: MagazineLayoutHeaderHeightMode = .dynamic 18 | 19 | let title: String 20 | 21 | init(title: String) { 22 | self.title = title 23 | } 24 | 25 | var diffHash: Int { 26 | return title.hashValue 27 | } 28 | 29 | func configurator() -> SupplementaryCellConfigurator { 30 | return HeaderHeadline2Configurator(item: self) 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Headers/SectionTitle/HeaderSectionTitle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderSectionTitle.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RxSwift 11 | import RxCocoa 12 | 13 | typealias HeaderSectionTitleConfigurator = MagazineSupplementaryCellConfigurator 14 | 15 | final class HeaderSectionTitle: UICollectionReusableView, ConfigurableCell { 16 | 17 | private let titleLabel: UILabel = { 18 | let l = UILabel(frame: .zero) 19 | l.bonMotStyle = Typography.Headline2 20 | return l 21 | }() 22 | 23 | private let subtitleLabel: UILabel = { 24 | let l = UILabel(frame: .zero) 25 | l.bonMotStyle = Typography.Caption 26 | l.textColor = UIColor.captionText 27 | return l 28 | }() 29 | 30 | override init(frame: CGRect) { 31 | super.init(frame: frame) 32 | 33 | self.addSubview(titleLabel) 34 | titleLabel.snp.makeConstraints { 35 | $0.leading.trailing.equalToSuperview() 36 | $0.top.equalToSuperview().offset(8) 37 | } 38 | 39 | self.addSubview(subtitleLabel) 40 | subtitleLabel.snp.makeConstraints { 41 | $0.leading.trailing.equalToSuperview() 42 | $0.top.equalTo(self.titleLabel.snp.bottom).offset(4) 43 | } 44 | } 45 | 46 | required init?(coder: NSCoder) { 47 | fatalError("init(coder:) has not been implemented") 48 | } 49 | 50 | func configure(item: HeaderSectionTitleVM) { 51 | titleLabel.styledText = item.title 52 | subtitleLabel.styledText = item.subtitle 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Headers/SectionTitle/HeaderSectionTitleVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderSectionTitleVM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | 12 | struct HeaderSectionTitleVM: MagazineSupplementaryDataType { 13 | 14 | let heightMode: MagazineLayoutHeaderHeightMode = .static(height: 64) 15 | 16 | let title: String 17 | let subtitle: String 18 | 19 | init(title: String, subtitle: String) { 20 | self.title = title 21 | self.subtitle = subtitle 22 | } 23 | 24 | var diffHash: Int { 25 | return title.hashValue 26 | } 27 | 28 | func configurator() -> SupplementaryCellConfigurator { 29 | return HeaderSectionTitleConfigurator(item: self) 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowCaption/RowCaption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowCaption.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | 12 | typealias RowCaptionConfigurator = MagazineCellConfigurator 13 | final class RowCaption: MagazineLayoutCollectionViewCell, ConfigurableCell { 14 | 15 | private let textLabel: UILabel = { 16 | let label = UILabel(frame: .zero) 17 | label.bonMotStyle = Typography.Caption 18 | label.numberOfLines = 0 19 | label.textColor = .captionText 20 | return label 21 | }() 22 | 23 | override init(frame: CGRect) { 24 | super.init(frame: frame) 25 | 26 | self.contentView.addSubview(textLabel) 27 | textLabel.snp.makeConstraints { 28 | $0.leading.trailing.equalToSuperview() 29 | $0.top.bottom.equalToSuperview() 30 | } 31 | } 32 | 33 | required init?(coder: NSCoder) { 34 | fatalError("init(coder:) has not been implemented") 35 | } 36 | 37 | func configure(item: RowCaptionVM) { 38 | self.textLabel.styledText = item.title 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowCaption/RowCaptionVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowCaptionVM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | struct RowCaptionVM: MagazineCellDataType { 16 | 17 | var sizeMode: MagazineLayoutItemSizeMode { 18 | return MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), 19 | heightMode: .dynamic) 20 | } 21 | 22 | let title: String 23 | 24 | init(title: String) { 25 | self.title = title 26 | } 27 | 28 | var diffHash: Int { 29 | return title.hashValue 30 | } 31 | 32 | func configurator() -> CellConfigurator { 33 | return RowCaptionConfigurator(item: self) 34 | } 35 | 36 | func didSelect() { 37 | // 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowDestinationTitle/RowDestinationTitle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowDestinationTitle.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | import RxSwift 12 | 13 | typealias RowDestinationTitleConfigurator = MagazineCellConfigurator 14 | final class RowDestinationTitle: MagazineLayoutCollectionViewCell, ConfigurableCell { 15 | 16 | static var nib: UINib? { return UINib(nibName: self.reuseIdentifier, bundle: nil) } 17 | 18 | @IBOutlet weak var textLabel: UILabel! 19 | @IBOutlet weak var likeButton: UIButton! 20 | 21 | private var bag = DisposeBag() 22 | 23 | func configure(item: RowDestinationTitleVM) { 24 | self.textLabel.styledText = item.title 25 | 26 | likeButton.rx.tap.scan(false) { lastState, newValue in 27 | return !lastState 28 | } 29 | .bind(to: self.likeButton.rx.isSelected) 30 | .disposed(by: bag) 31 | } 32 | 33 | override func prepareForReuse() { 34 | super.prepareForReuse() 35 | self.bag = DisposeBag() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowDestinationTitle/RowDestinationTitle.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 32 | 42 | 50 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowDestinationTitle/RowDestinationTitleVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowDestinationTitleVM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | final class RowDestinationTitleVM: MagazineCellDataType { 16 | 17 | var sizeMode: MagazineLayoutItemSizeMode { 18 | return MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), 19 | heightMode: .static(height: 72)) 20 | } 21 | 22 | let title: String 23 | 24 | init(title: String) { 25 | self.title = title 26 | } 27 | 28 | var diffHash: Int { 29 | return title.hashValue 30 | } 31 | 32 | func configurator() -> CellConfigurator { 33 | return RowDestinationTitleConfigurator(item: self) 34 | } 35 | 36 | func didSelect() { 37 | // 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowFlightInfo/RowFlightInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowFlightInfo.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | 12 | typealias RowFlightInfoConfigurator = MagazineCellConfigurator 13 | final class RowFlightInfo: MagazineLayoutCollectionViewCell, ConfigurableCell { 14 | 15 | static var nib: UINib? { return UINib(nibName: self.reuseIdentifier, bundle: nil) } 16 | 17 | @IBOutlet weak var departureTimeLabel: UILabel! 18 | @IBOutlet weak var arrivalTimeLabel: UILabel! 19 | @IBOutlet weak var departureDestinationLabel: UILabel! 20 | @IBOutlet weak var arrivalDestinationLabel: UILabel! 21 | 22 | func configure(item: RowFlightInfoVM) { 23 | self.departureTimeLabel.styledText = item.flightInfo.departureTime 24 | self.departureDestinationLabel.styledText = item.flightInfo.departureAirport 25 | 26 | self.arrivalTimeLabel.styledText = item.flightInfo.arrivalTime 27 | self.arrivalDestinationLabel.styledText = item.flightInfo.arrivalAirport 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowFlightInfo/RowFlightInfo.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowFlightInfo/RowFlightInfoVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowFlightInfoVM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | struct FlightInfo: Hashable { 16 | let departureTime: String 17 | let departureAirport: String 18 | 19 | let arrivalTime: String 20 | let arrivalAirport: String 21 | } 22 | 23 | struct RowFlightInfoVM: MagazineCellDataType { 24 | 25 | var sizeMode: MagazineLayoutItemSizeMode { 26 | return MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), 27 | heightMode: .static(height: 60)) 28 | } 29 | 30 | let flightInfo: FlightInfo 31 | 32 | init(info: FlightInfo) { 33 | self.flightInfo = info 34 | } 35 | 36 | var diffHash: Int { 37 | return flightInfo.hashValue 38 | } 39 | 40 | func configurator() -> CellConfigurator { 41 | return RowFlightInfoConfigurator(item: self) 42 | } 43 | 44 | func didSelect() { 45 | // 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowHeadline1/RowHeadline1.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowHeadline1.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 12/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | import SnapKit 12 | import BonMot 13 | 14 | typealias RowHeadline1Configurator = MagazineCellConfigurator 15 | final class RowHeadline1: MagazineLayoutCollectionViewCell, ConfigurableCell { 16 | 17 | private let textLabel: UILabel = { 18 | let label = UILabel(frame: .zero) 19 | label.bonMotStyle = Typography.Headline1 20 | label.numberOfLines = 0 21 | label.textColor = .mainText 22 | return label 23 | }() 24 | 25 | override init(frame: CGRect) { 26 | super.init(frame: frame) 27 | 28 | self.contentView.addSubview(textLabel) 29 | textLabel.snp.makeConstraints { 30 | $0.leading.trailing.equalToSuperview() 31 | $0.top.bottom.equalToSuperview().inset(8) 32 | } 33 | } 34 | 35 | required init?(coder: NSCoder) { 36 | fatalError("init(coder:) has not been implemented") 37 | } 38 | 39 | func configure(item: RowHeadline1VM) { 40 | self.textLabel.styledText = item.title 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowHeadline1/RowHeadline1VM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowHeadline1VM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 12/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | struct RowHeadline1VM: MagazineCellDataType { 16 | 17 | var sizeMode: MagazineLayoutItemSizeMode { 18 | return MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), 19 | heightMode: .dynamic) 20 | } 21 | 22 | let title: String 23 | 24 | init(title: String) { 25 | self.title = title 26 | } 27 | 28 | var diffHash: Int { 29 | return title.hashValue 30 | } 31 | 32 | func configurator() -> CellConfigurator { 33 | return RowHeadline1Configurator(item: self) 34 | } 35 | 36 | func didSelect() { 37 | // 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowHorizontalCardsCollection/CardsHorizontalRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardsHorizontalRow.swift 3 | // Chili Labs 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | import RxSwift 12 | import RxFlow 13 | import SnapKit 14 | 15 | typealias RowHorizontalCardsCollectionConfigurator = MagazineCellConfigurator 16 | 17 | final class RowHorizontalCardsCollection: UICollectionViewCell, ConfigurableCell { 18 | 19 | lazy var collectionView: UICollectionView = { 20 | let layout = UICollectionViewFlowLayout() 21 | layout.itemSize = CGSize(width: 50, height: 50) 22 | layout.minimumLineSpacing = 16 23 | layout.minimumInteritemSpacing = 0 24 | layout.scrollDirection = .horizontal 25 | let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) 26 | collectionView.isPrefetchingEnabled = true 27 | collectionView.dataSource = self 28 | collectionView.delegate = self 29 | collectionView.backgroundColor = .white 30 | collectionView.contentInsetAdjustmentBehavior = .always 31 | collectionView.showsHorizontalScrollIndicator = false 32 | collectionView.clipsToBounds = false 33 | collectionView.contentInset = UIEdgeInsets(top: 0, left: 32, bottom: 0, right: 16) 34 | 35 | return collectionView 36 | }() 37 | 38 | private var items = [CellConfigurator]() 39 | private lazy var cellsRegistrator = CollectionViewCellsRegistrator(collectionView: self.collectionView) 40 | private var bag = DisposeBag() 41 | 42 | override init(frame: CGRect) { 43 | super.init(frame: frame) 44 | 45 | self.addSubview(self.collectionView) 46 | collectionView.snp.makeConstraints { $0.edges.equalTo(0) } 47 | 48 | self.clipsToBounds = false 49 | } 50 | 51 | required init?(coder aDecoder: NSCoder) { 52 | fatalError("init(coder:) has not been implemented") 53 | } 54 | 55 | func configure(item: RowHorizontalCardsCollectionVM) { 56 | (self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.itemSize = CGSize(width: item.itemWidth, height: item.itemHeight) 57 | let configs = item.configurators 58 | self.cellsRegistrator.register(cellConfigs: configs) 59 | (self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing = item.itemsSpacing 60 | self.items = configs 61 | self.collectionView.reloadData() 62 | } 63 | 64 | override func prepareForReuse() { 65 | super.prepareForReuse() 66 | self.bag = DisposeBag() 67 | self.collectionView.contentOffset = CGPoint(x: -collectionView.contentInset.left, y: 0) 68 | } 69 | } 70 | 71 | extension RowHorizontalCardsCollection: UICollectionViewDataSource, UICollectionViewDelegate { 72 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 73 | return items.count 74 | } 75 | 76 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 77 | let cellConfigurator = items[indexPath.row] 78 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: type(of: cellConfigurator).cellReuseIdentifier, for: indexPath) 79 | cellConfigurator.configure(cell: cell) 80 | return cell 81 | } 82 | 83 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 84 | let cellConfigurator = items[indexPath.row] 85 | cellConfigurator.didSelect() 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowHorizontalCardsCollection/CardsHorizontalRowVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowHorizontalCardsCollectionVM.swift 3 | // Chili Labs 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | final class RowHorizontalCardsCollectionVM: MagazineCellDataType, Stepper { 16 | let steps = PublishRelay() 17 | 18 | lazy private(set) var sizeMode = MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), 19 | heightMode: .static(height: self.itemHeight)) 20 | 21 | let items: [MagazineCellDataType] 22 | 23 | private let bag = DisposeBag() 24 | 25 | let itemWidth: CGFloat 26 | let itemHeight: CGFloat 27 | let itemsSpacing: CGFloat 28 | 29 | var configurators: [CellConfigurator] { 30 | return items.map({ $0.configurator()}) 31 | } 32 | 33 | init(items: [MagazineCellDataType], itemWidth: CGFloat, itemHeight: CGFloat, itemsSpacing: CGFloat = 16) { 34 | self.items = items 35 | self.itemWidth = itemWidth 36 | self.itemHeight = itemHeight 37 | self.itemsSpacing = itemsSpacing 38 | self.items.forEach { [unowned self] vm in 39 | (vm as? Stepper)?.steps.bind(to: self.steps).disposed(by: self.bag) 40 | } 41 | } 42 | 43 | var diffHash: Int { 44 | return items.map({ $0.diffHash }).reduce(0, ^) 45 | } 46 | 47 | func didSelect() { 48 | //do nothing as this cell is just a container 49 | } 50 | 51 | func configurator() -> CellConfigurator { 52 | return RowHorizontalCardsCollectionConfigurator(item: self) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowText/RowText.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowText.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MagazineLayout 11 | 12 | typealias RowTextConfigurator = MagazineCellConfigurator 13 | final class RowText: MagazineLayoutCollectionViewCell, ConfigurableCell { 14 | 15 | private let textLabel: UILabel = { 16 | let label = UILabel(frame: .zero) 17 | label.bonMotStyle = Typography.Text 18 | label.numberOfLines = 0 19 | label.textColor = .captionText 20 | return label 21 | }() 22 | 23 | override init(frame: CGRect) { 24 | super.init(frame: frame) 25 | 26 | self.contentView.addSubview(textLabel) 27 | textLabel.snp.makeConstraints { 28 | $0.leading.trailing.equalToSuperview() 29 | $0.top.bottom.equalToSuperview() 30 | } 31 | } 32 | 33 | required init?(coder: NSCoder) { 34 | fatalError("init(coder:) has not been implemented") 35 | } 36 | 37 | func configure(item: RowTextVM) { 38 | textLabel.styledText = item.text 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Rows/RowText/RowTextVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RowTextVM.swift 3 | // Chili Labs 4 | // 5 | // Generated by Chigevara on 14/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MagazineLayout 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | struct RowTextVM: MagazineCellDataType { 16 | 17 | var sizeMode: MagazineLayoutItemSizeMode { 18 | return MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), 19 | heightMode: .dynamic) 20 | } 21 | 22 | let text: String 23 | 24 | init(text: String) { 25 | self.text = text 26 | } 27 | 28 | var diffHash: Int { 29 | return text.hashValue 30 | } 31 | 32 | func configurator() -> CellConfigurator { 33 | return RowTextConfigurator(item: self) 34 | } 35 | 36 | func didSelect() { 37 | // 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Classes/UI/DesignSystem/Typography/Typography.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Typography.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import BonMot 11 | 12 | enum Typography { 13 | static let Headline1 = StringStyle( 14 | .font(UIFont.systemFont(ofSize: 32, weight: .medium)) 15 | ) 16 | 17 | static let Headline2 = StringStyle( 18 | .font(UIFont.systemFont(ofSize: 24, weight: .bold)) 19 | ) 20 | 21 | static let Headline3 = StringStyle( 22 | .font(UIFont.systemFont(ofSize: 20, weight: .semibold)) 23 | ) 24 | 25 | static let Headline4 = StringStyle( 26 | .font(UIFont.systemFont(ofSize: 18, weight: .semibold)) 27 | ) 28 | 29 | static let Caption = StringStyle( 30 | .font(UIFont.systemFont(ofSize: 14, weight: .regular)) 31 | ) 32 | 33 | static let Caption2 = StringStyle( 34 | .font(UIFont.systemFont(ofSize: 12, weight: .regular)) 35 | ) 36 | 37 | static let DateTime = StringStyle( 38 | .font(UIFont.systemFont(ofSize: 22, weight: .semibold)) 39 | ) 40 | 41 | static let Text = StringStyle( 42 | .font(UIFont.systemFont(ofSize: 15, weight: .regular)), 43 | .lineHeightMultiple(1.5) 44 | ) 45 | 46 | static func registerAllStyles() { 47 | NamedStyles.shared.registerStyle(forName: "Headline1", style: Headline1) 48 | NamedStyles.shared.registerStyle(forName: "Headline2", style: Headline2) 49 | NamedStyles.shared.registerStyle(forName: "Headline3", style: Headline3) 50 | NamedStyles.shared.registerStyle(forName: "Headline4", style: Headline4) 51 | NamedStyles.shared.registerStyle(forName: "Caption", style: Caption) 52 | NamedStyles.shared.registerStyle(forName: "Caption2", style: Caption2) 53 | NamedStyles.shared.registerStyle(forName: "DateTime", style: DateTime) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Classes/UI/Explore/ExploreVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExploreVM.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | import RxCocoa 12 | import RxFlow 13 | 14 | final class ExploreVM: SectionedViewModel { 15 | 16 | @VMProperty([]) var sections: Observable<[MagazineLayoutSection]> 17 | 18 | let steps = PublishRelay() 19 | private let bag = DisposeBag() 20 | 21 | init() { 22 | 23 | let destinations = [ 24 | CardDestinationVM(imageUrl: "http://chililabs.io/images/opensource/ios_design_system/img_1.jpg", 25 | title: "Maldives", 26 | subtitle: "34 people visited", 27 | step: FlowStep.Explore.page), 28 | CardDestinationVM(imageUrl: "http://chililabs.io/images/opensource/ios_design_system/img_2.jpg", 29 | title: "Egypt", 30 | subtitle: "129 people visited", 31 | step: FlowStep.Explore.page), 32 | CardDestinationVM(imageUrl: "http://chililabs.io/images/opensource/ios_design_system/img_3.jpg", 33 | title: "Bali", 34 | subtitle: "87 people visited", 35 | step: FlowStep.Explore.page) 36 | ] 37 | 38 | let header = HeaderSectionTitleVM(title: "Last visited", subtitle: "Your last visited destinations") 39 | 40 | $sections.accept( 41 | [ 42 | MagazineLayoutSection(items: [ 43 | RowHeadline1VM(title: "Explore new places and meet new people").configurator(), 44 | RowCaptionVM(title: "Most popular destinations").configurator() 45 | ], sectionInset: UIEdgeInsets(top: 16, left: 32, bottom: 16, right: 16)), 46 | MagazineLayoutSection(items: [ 47 | RowHorizontalCardsCollectionVM(items: destinations, 48 | itemWidth: 136, 49 | itemHeight: 224, 50 | itemsSpacing: 8).configurator() 51 | ], sectionInset: UIEdgeInsets(top: 24, left: 0, bottom: 24, right: 0)), 52 | MagazineLayoutSection(items: [ 53 | RowFlightInfoVM(info: FlightInfo(departureTime: "05:00", 54 | departureAirport: "Riga (RIX)", 55 | arrivalTime: "20:00", 56 | arrivalAirport: "Tokyo (HND)")).configurator(), 57 | RowFlightInfoVM(info: FlightInfo(departureTime: "14:00", 58 | departureAirport: "Riga (RIX)", 59 | arrivalTime: "23:30", 60 | arrivalAirport: "Bali (DPS)")).configurator(), 61 | 62 | RowFlightInfoVM(info: FlightInfo(departureTime: "07:30", 63 | departureAirport: "Riga (RIX)", 64 | arrivalTime: "12:15", 65 | arrivalAirport: "Cyprus (LCA)")).configurator() 66 | ], 67 | header: .init(item: header.configurator(), visibilityMode: .visible(heightMode: header.heightMode)), 68 | sectionInset: UIEdgeInsets(top: 24, left: 32, bottom: 32, right: 16)) 69 | 70 | ] 71 | ) 72 | 73 | destinations.forEach { 74 | $0.steps.bind(to: self.steps).disposed(by: bag) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Classes/UI/Flow/AppFlow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Igors Nemenonoks on 2019-05-10. 3 | // Copyright (c) 2019 Chili Labs. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | import UIKit 8 | import RxFlow 9 | import RxCocoa 10 | import RxSwift 11 | 12 | final class AppFlow: Flow { 13 | var root: Presentable { 14 | return self.rootWindow 15 | } 16 | 17 | private let rootWindow: UIWindow 18 | 19 | init(withWindow window: UIWindow) { 20 | self.rootWindow = window 21 | } 22 | 23 | func navigate(to step: Step) -> FlowContributors { 24 | switch step { 25 | case let authStep as FlowStep.Explore: 26 | return handleExploreNavigation(for: authStep) 27 | default: 28 | return .none 29 | } 30 | } 31 | 32 | private func handleExploreNavigation(for step: FlowStep.Explore) -> FlowContributors { 33 | let mainFlow = ExploreFlow() 34 | Flows.whenReady(flow1: mainFlow) { [unowned self] (root) in 35 | self.rootWindow.rootViewController = root 36 | } 37 | 38 | return .one(flowContributor: .contribute(withNextPresentable: mainFlow, 39 | withNextStepper: OneStepper(withSingleStep: step))) 40 | } 41 | } 42 | 43 | final class AppStepper: Stepper { 44 | 45 | let steps = PublishRelay() 46 | private let disposeBag = DisposeBag() 47 | 48 | var initialStep: Step { 49 | return FlowStep.Explore.main 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Classes/UI/Flow/ExploreFlow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExploreFlow.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import RxFlow 12 | import RxSwift 13 | import RxCocoa 14 | 15 | final class ExploreFlow: Flow { 16 | var root: Presentable { 17 | return self.rootViewController 18 | } 19 | 20 | let rootViewController: UINavigationController = { 21 | let nc = NavigationController() 22 | nc.navigationBar.isHidden = true 23 | return nc 24 | }() 25 | 26 | private let bag = DisposeBag() 27 | 28 | func navigate(to step: Step) -> FlowContributors { 29 | guard let step = step as? FlowStep.Explore else { return .none } 30 | switch step { 31 | case .main: 32 | return navigateToDashboard() 33 | case .page: 34 | return navigateToPage() 35 | case .pop: 36 | self.rootViewController.popViewController(animated: true) 37 | return .none 38 | } 39 | } 40 | 41 | private func navigateToDashboard() -> FlowContributors { 42 | let vm = ExploreVM() 43 | let vc = Screen(viewModel: vm) 44 | self.rootViewController.viewControllers = [vc] 45 | return .one(flowContributor: .contribute(withNextPresentable: vc, withNextStepper: vm)) 46 | } 47 | 48 | private func navigateToPage() -> FlowContributors { 49 | let vm = DestinationVM() 50 | let vc = DestinationVC(viewModel: vm) 51 | self.rootViewController.pushViewController(vc, animated: true) 52 | return .one(flowContributor: .contribute(withNextPresentable: vc, withNextStepper: vm)) 53 | } 54 | } 55 | 56 | final class NavigationController: UINavigationController { 57 | override var preferredStatusBarStyle: UIStatusBarStyle { 58 | return topViewController?.preferredStatusBarStyle ?? super.preferredStatusBarStyle 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Classes/UI/Flow/FlowStep.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Igors Nemenonoks on 2019-05-10. 3 | // Copyright (c) 2019 Chili Labs. All rights reserved. 4 | // 5 | 6 | import Foundation 7 | import RxFlow 8 | import MapKit 9 | 10 | enum FlowStep { 11 | enum Explore: Step { 12 | case main 13 | case page 14 | case pop 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Classes/UI/Page/DestinationVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DestinationVC.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import RxSwift 12 | import RxFlow 13 | import MXParallaxHeader 14 | 15 | final class DestinationVC: Screen { 16 | 17 | private let bag = DisposeBag() 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | 22 | addHeader() 23 | } 24 | 25 | private func addHeader() { 26 | let headerView: HeaderDestination = HeaderDestination.viewFromXib() 27 | 28 | collectionView.parallaxHeader.view = headerView 29 | collectionView.parallaxHeader.height = HeaderDestination.height 30 | collectionView.parallaxHeader.minimumHeight = HeaderDestination.minimumHeight 31 | collectionView.parallaxHeader.mode = .fill 32 | 33 | headerView.widthAnchor.constraint(equalTo: collectionView.widthAnchor).isActive = true 34 | 35 | headerView.backButton.rx.tap 36 | .map({ FlowStep.Explore.pop }) 37 | .bind(to: self.viewModel.steps) 38 | .disposed(by: bag) 39 | } 40 | 41 | override var preferredStatusBarStyle: UIStatusBarStyle { 42 | return .lightContent 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Classes/UI/Page/DestinationVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DestinationVM.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 13/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | import RxCocoa 12 | import RxFlow 13 | 14 | final class DestinationVM: SectionedViewModel { 15 | 16 | @VMProperty([]) var sections: Observable<[MagazineLayoutSection]> 17 | 18 | let steps = PublishRelay() 19 | private let bag = DisposeBag() 20 | 21 | init() { 22 | let header1 = HeaderHeadline2VM(title: "Introduction") 23 | let header2 = HeaderHeadline2VM(title: "Places to see") 24 | 25 | $sections.accept([ 26 | MagazineLayoutSection(items: [ 27 | RowDestinationTitleVM(title: "Indonesia, Bali").configurator() 28 | ], sectionInset: UIEdgeInsets(top: 0, left: 32, bottom: 16, right: 16)), 29 | MagazineLayoutSection(items: [ 30 | RowTextVM(text: "Bali is an Indonesian island known for its forested volcanic mountains, iconic rice paddies, white beaches and coral reefs. The island is home to religious sites such as cliffside Uluwatu Temple. The island is also known for its yoga and meditation retreats.").configurator() 31 | ], header: .init(item: header1.configurator(), 32 | visibilityMode: .visible(heightMode: header1.heightMode, pinToVisibleBounds: false)), 33 | sectionInset: UIEdgeInsets(top: 0, left: 32, bottom: 16, right: 16)), 34 | MagazineLayoutSection(items: [ 35 | RowHorizontalCardsCollectionVM(items: [ 36 | CardPhotoThumbnailVM(url: "https://upload.wikimedia.org/wikipedia/commons/5/5e/Uluwatu%40bali.jpg"), 37 | CardPhotoThumbnailVM(url: "https://p1.pxfuel.com/preview/458/393/320/bali-tour-packages-book-bali-honeymoon-packages-bali-holiday-packages-best-travel-agency-in-delhi.jpg"), 38 | CardPhotoThumbnailVM(url: "https://cdn.pixabay.com/photo/2017/06/07/05/10/ubud-bali-2379365_960_720.jpg"), 39 | CardPhotoThumbnailVM(url: "https://dimg04.c-ctrip.com/images/200t0x000000kx593CDF5_R_550_412_R5_Q70_D.jpg") 40 | ], 41 | itemWidth: 164, 42 | itemHeight: 120, 43 | itemsSpacing: 8).configurator() 44 | ], header: .init(item: header2.configurator(), 45 | visibilityMode: .visible(heightMode: header1.heightMode, pinToVisibleBounds: false)), 46 | sectionInset: UIEdgeInsets(top: 16, left: 32, bottom: 32, right: 16), 47 | itemsInset: UIEdgeInsets(top: 8, left: -32, bottom: 0, right: -16)) 48 | ]) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Classes/UI/Utils/Reusable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reusable.swift 3 | // 4 | // Created by Igors Nemenonoks on 17/11/16. 5 | // Copyright © 2020 Chili Labs. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | public protocol Reusable: class { 11 | static var reuseIdentifier: String { get } 12 | static var nib: UINib? { get } 13 | } 14 | 15 | public extension Reusable { 16 | static var reuseIdentifier: String { return String(describing: Self.self) } 17 | static var nib: UINib? { return nil } 18 | } 19 | 20 | extension UICollectionView { 21 | public func registerReusableCell(_: T.Type) where T: Reusable { 22 | if let nib = T.nib { 23 | self.register(nib, forCellWithReuseIdentifier: T.reuseIdentifier) 24 | } else { 25 | self.register(T.self, forCellWithReuseIdentifier: T.reuseIdentifier) 26 | } 27 | } 28 | 29 | public func dequeueReusableCell(indexPath: IndexPath) -> T where T: Reusable { 30 | return self.dequeueReusableCell(withReuseIdentifier: T.reuseIdentifier, for: indexPath) as! T 31 | } 32 | public func dequeueReusableSupplementaryView(ofKind kind: String, indexPath: IndexPath) -> T where T: Reusable { 33 | return self.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: T.reuseIdentifier, for: indexPath) as! T 34 | } 35 | } 36 | 37 | public extension String { 38 | static func className(_ obj: AnyObject) -> String { 39 | return String(describing:obj.self).components(separatedBy: ".").last! 40 | } 41 | 42 | static func className(_ cls: AnyClass) -> String { 43 | return String(describing:cls).components(separatedBy: ".").last! 44 | } 45 | } 46 | 47 | extension UIView { 48 | public static func viewFromXib(_ aBundle: Bundle? = nil) -> T { 49 | return UINib(nibName: String.className(T.self), bundle: aBundle).instantiate(withOwner: nil, options: nil)[0] as! T 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Classes/UI/Utils/RxUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RxUtils.swift 3 | // DesignSystemExample 4 | // 5 | // Created by Igors Nemenonoks on 19/05/2020. 6 | // Copyright © 2020 Chili Labs. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import RxSwift 11 | import RxCocoa 12 | 13 | @propertyWrapper 14 | struct VMProperty { 15 | 16 | private let relay: BehaviorRelay 17 | 18 | init(_ defaultValue: Type) { 19 | self.relay = .init(value: defaultValue) 20 | } 21 | 22 | var wrappedValue: Observable { 23 | return relay.asObservable() 24 | } 25 | 26 | var projectedValue: BehaviorRelay { 27 | return relay 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Demo/mockup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Demo/mockup.gif -------------------------------------------------------------------------------- /DesignSystemExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 04D3491EBF034C557B0624BD /* CellConfigurators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1DDB77D41F8E5654210256 /* CellConfigurators.swift */; }; 11 | 4929660F2473B88A0061C94E /* RxUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4929660E2473B88A0061C94E /* RxUtils.swift */; }; 12 | 49760BA624699AFF00FEFD61 /* Reusable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BA524699AFF00FEFD61 /* Reusable.swift */; }; 13 | 49760BB8246B0B3900FEFD61 /* RowHeadline1VM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BB6246B0B3900FEFD61 /* RowHeadline1VM.swift */; }; 14 | 49760BB9246B0B3900FEFD61 /* RowHeadline1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BB7246B0B3900FEFD61 /* RowHeadline1.swift */; }; 15 | 49760BBC246BCBE100FEFD61 /* ExploreVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BBB246BCBE100FEFD61 /* ExploreVM.swift */; }; 16 | 49760BBE246BCDA300FEFD61 /* ExploreFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BBD246BCDA300FEFD61 /* ExploreFlow.swift */; }; 17 | 49760BC1246BCF4700FEFD61 /* Typography.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BC0246BCF4700FEFD61 /* Typography.swift */; }; 18 | 49760BC4246BD13000FEFD61 /* UIColor+Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BC3246BD13000FEFD61 /* UIColor+Styles.swift */; }; 19 | 49760BC8246BD5D900FEFD61 /* RowCaption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BC6246BD5D900FEFD61 /* RowCaption.swift */; }; 20 | 49760BC9246BD5D900FEFD61 /* RowCaptionVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BC7246BD5D900FEFD61 /* RowCaptionVM.swift */; }; 21 | 49760BCF246BEB6400FEFD61 /* CardsHorizontalRowVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BCD246BEB6400FEFD61 /* CardsHorizontalRowVM.swift */; }; 22 | 49760BD0246BEB6400FEFD61 /* CardsHorizontalRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BCE246BEB6400FEFD61 /* CardsHorizontalRow.swift */; }; 23 | 49760BD4246BEF3B00FEFD61 /* CardDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BD2246BEF3A00FEFD61 /* CardDestination.swift */; }; 24 | 49760BD5246BEF3B00FEFD61 /* CardDestinationVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BD3246BEF3A00FEFD61 /* CardDestinationVM.swift */; }; 25 | 49760BDA246C261F00FEFD61 /* HeaderSectionTitleVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BD8246C261F00FEFD61 /* HeaderSectionTitleVM.swift */; }; 26 | 49760BDB246C261F00FEFD61 /* HeaderSectionTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BD9246C261F00FEFD61 /* HeaderSectionTitle.swift */; }; 27 | 49760BE0246C312700FEFD61 /* RowFlightInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BDE246C312700FEFD61 /* RowFlightInfo.swift */; }; 28 | 49760BE1246C312700FEFD61 /* RowFlightInfoVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BDF246C312700FEFD61 /* RowFlightInfoVM.swift */; }; 29 | 49760BE3246C31C200FEFD61 /* RowFlightInfo.xib in Resources */ = {isa = PBXBuildFile; fileRef = 49760BE2246C31C200FEFD61 /* RowFlightInfo.xib */; }; 30 | 49760BE6246C44C800FEFD61 /* DestinationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BE5246C44C800FEFD61 /* DestinationVC.swift */; }; 31 | 49760BE9246C45BD00FEFD61 /* HeaderDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BE8246C45BD00FEFD61 /* HeaderDestination.swift */; }; 32 | 49760BEB246C45D500FEFD61 /* HeaderDestination.xib in Resources */ = {isa = PBXBuildFile; fileRef = 49760BEA246C45D500FEFD61 /* HeaderDestination.xib */; }; 33 | 49760BF1246D1F2700FEFD61 /* RowDestinationTitleVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BEF246D1F2700FEFD61 /* RowDestinationTitleVM.swift */; }; 34 | 49760BF2246D1F2700FEFD61 /* RowDestinationTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BF0246D1F2700FEFD61 /* RowDestinationTitle.swift */; }; 35 | 49760BF6246D1F3100FEFD61 /* HeaderHeadline2VM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BF4246D1F3100FEFD61 /* HeaderHeadline2VM.swift */; }; 36 | 49760BF7246D1F3100FEFD61 /* HeaderHeadline2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BF5246D1F3100FEFD61 /* HeaderHeadline2.swift */; }; 37 | 49760BF9246D1FAD00FEFD61 /* RowDestinationTitle.xib in Resources */ = {isa = PBXBuildFile; fileRef = 49760BF8246D1FAD00FEFD61 /* RowDestinationTitle.xib */; }; 38 | 49760BFB246D2A0F00FEFD61 /* DestinationVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BFA246D2A0F00FEFD61 /* DestinationVM.swift */; }; 39 | 49760BFF246D2C4F00FEFD61 /* RowText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BFD246D2C4F00FEFD61 /* RowText.swift */; }; 40 | 49760C00246D2C4F00FEFD61 /* RowTextVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760BFE246D2C4F00FEFD61 /* RowTextVM.swift */; }; 41 | 49760C04246D2E2000FEFD61 /* CardPhotoThumbnail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760C02246D2E1F00FEFD61 /* CardPhotoThumbnail.swift */; }; 42 | 49760C05246D2E2000FEFD61 /* CardPhotoThumbnailVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49760C03246D2E1F00FEFD61 /* CardPhotoThumbnailVM.swift */; }; 43 | 57025306DF211B937B09467A /* AppFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9223680A65A94EEE31B7939 /* AppFlow.swift */; }; 44 | 7836C978DD3EF1B13922EA51 /* FlowStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1737C250A31319ABC50B29 /* FlowStep.swift */; }; 45 | 7FE0B7AB2105FF48BF2A460F /* Icons.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37375CAB15538E0540D15D45 /* Icons.xcassets */; }; 46 | 839A9D96EB313DD94FA58E22 /* MagazineLayoutSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24CE7E516BA1C742535515A8 /* MagazineLayoutSection.swift */; }; 47 | 95DD07E8976969469D3191FA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9839CA0B4CB5CDC640AEF89 /* AppDelegate.swift */; }; 48 | 9986536FED1C215480292268 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2D912EEB6348114B3A4FF1B8 /* Localizable.strings */; }; 49 | ABB6B97D199EC99BF1B1867B /* BaseMagazineLayoutVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59108EA44C86F3235B966D8B /* BaseMagazineLayoutVC.swift */; }; 50 | AF3EFA21160AF3257FF42D31 /* CollectionViewCellsRegistrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46377B511079178264596B00 /* CollectionViewCellsRegistrator.swift */; }; 51 | C7113BB953D5AA27AB0C3CD1 /* StepSupportable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F076547F3877FA786B0B88C /* StepSupportable.swift */; }; 52 | D7ABC8DDF8AE396533866E45 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9774B0C6FB809C81934FD6D6 /* LaunchScreen.storyboard */; }; 53 | DB28D28E89BDF6803F9624F0 /* Pods_DesignSystemExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57CC472D17DA59D0542A9685 /* Pods_DesignSystemExample.framework */; }; 54 | F2E98AA4069B277626889811 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 36E32FD601B4C8B3204C4B48 /* Main.storyboard */; }; 55 | F88F21E51666FA41FF4A275F /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383D08CC216E24568F227648 /* Screen.swift */; }; 56 | /* End PBXBuildFile section */ 57 | 58 | /* Begin PBXContainerItemProxy section */ 59 | 216F8559619519337020F075 /* PBXContainerItemProxy */ = { 60 | isa = PBXContainerItemProxy; 61 | containerPortal = 15C6769C3FF9813D7AA4DC60 /* Project object */; 62 | proxyType = 1; 63 | remoteGlobalIDString = EADCFA617F448DCA4A19BD95; 64 | remoteInfo = DesignSystemExample; 65 | }; 66 | /* End PBXContainerItemProxy section */ 67 | 68 | /* Begin PBXCopyFilesBuildPhase section */ 69 | 778909214512A9D9E3353F33 /* Embed Frameworks */ = { 70 | isa = PBXCopyFilesBuildPhase; 71 | buildActionMask = 2147483647; 72 | dstSubfolderSpec = 10; 73 | files = ( 74 | ); 75 | name = "Embed Frameworks"; 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | C96A27622B98ED2B9E6CBACC /* Embed Frameworks */ = { 79 | isa = PBXCopyFilesBuildPhase; 80 | buildActionMask = 2147483647; 81 | dstSubfolderSpec = 10; 82 | files = ( 83 | ); 84 | name = "Embed Frameworks"; 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXCopyFilesBuildPhase section */ 88 | 89 | /* Begin PBXFileReference section */ 90 | 1F076547F3877FA786B0B88C /* StepSupportable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepSupportable.swift; sourceTree = ""; }; 91 | 1F1DDB77D41F8E5654210256 /* CellConfigurators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CellConfigurators.swift; sourceTree = ""; }; 92 | 24985D79969B12C8E94D111C /* DesignSystemExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DesignSystemExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 93 | 24CE7E516BA1C742535515A8 /* MagazineLayoutSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagazineLayoutSection.swift; sourceTree = ""; }; 94 | 2D912EEB6348114B3A4FF1B8 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; 95 | 2FCEC3565E97C3F5B74EA79F /* Pods-DesignSystemExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DesignSystemExample.release.xcconfig"; path = "Target Support Files/Pods-DesignSystemExample/Pods-DesignSystemExample.release.xcconfig"; sourceTree = ""; }; 96 | 32B94D0248D350885B40EACE /* DesignSystemExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DesignSystemExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | 36E32FD601B4C8B3204C4B48 /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 98 | 37375CAB15538E0540D15D45 /* Icons.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Icons.xcassets; sourceTree = ""; }; 99 | 383D08CC216E24568F227648 /* Screen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Screen.swift; sourceTree = ""; }; 100 | 46377B511079178264596B00 /* CollectionViewCellsRegistrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewCellsRegistrator.swift; sourceTree = ""; }; 101 | 4929660E2473B88A0061C94E /* RxUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxUtils.swift; sourceTree = ""; }; 102 | 49760BA524699AFF00FEFD61 /* Reusable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reusable.swift; sourceTree = ""; }; 103 | 49760BB6246B0B3900FEFD61 /* RowHeadline1VM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowHeadline1VM.swift; sourceTree = ""; }; 104 | 49760BB7246B0B3900FEFD61 /* RowHeadline1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowHeadline1.swift; sourceTree = ""; }; 105 | 49760BBB246BCBE100FEFD61 /* ExploreVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreVM.swift; sourceTree = ""; }; 106 | 49760BBD246BCDA300FEFD61 /* ExploreFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreFlow.swift; sourceTree = ""; }; 107 | 49760BC0246BCF4700FEFD61 /* Typography.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typography.swift; sourceTree = ""; }; 108 | 49760BC3246BD13000FEFD61 /* UIColor+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Styles.swift"; sourceTree = ""; }; 109 | 49760BC6246BD5D900FEFD61 /* RowCaption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowCaption.swift; sourceTree = ""; }; 110 | 49760BC7246BD5D900FEFD61 /* RowCaptionVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowCaptionVM.swift; sourceTree = ""; }; 111 | 49760BCD246BEB6400FEFD61 /* CardsHorizontalRowVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardsHorizontalRowVM.swift; sourceTree = ""; }; 112 | 49760BCE246BEB6400FEFD61 /* CardsHorizontalRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardsHorizontalRow.swift; sourceTree = ""; }; 113 | 49760BD2246BEF3A00FEFD61 /* CardDestination.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardDestination.swift; sourceTree = ""; }; 114 | 49760BD3246BEF3A00FEFD61 /* CardDestinationVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardDestinationVM.swift; sourceTree = ""; }; 115 | 49760BD8246C261F00FEFD61 /* HeaderSectionTitleVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderSectionTitleVM.swift; sourceTree = ""; }; 116 | 49760BD9246C261F00FEFD61 /* HeaderSectionTitle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderSectionTitle.swift; sourceTree = ""; }; 117 | 49760BDE246C312700FEFD61 /* RowFlightInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowFlightInfo.swift; sourceTree = ""; }; 118 | 49760BDF246C312700FEFD61 /* RowFlightInfoVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowFlightInfoVM.swift; sourceTree = ""; }; 119 | 49760BE2246C31C200FEFD61 /* RowFlightInfo.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RowFlightInfo.xib; sourceTree = ""; }; 120 | 49760BE5246C44C800FEFD61 /* DestinationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestinationVC.swift; sourceTree = ""; }; 121 | 49760BE8246C45BD00FEFD61 /* HeaderDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderDestination.swift; sourceTree = ""; }; 122 | 49760BEA246C45D500FEFD61 /* HeaderDestination.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HeaderDestination.xib; sourceTree = ""; }; 123 | 49760BEF246D1F2700FEFD61 /* RowDestinationTitleVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowDestinationTitleVM.swift; sourceTree = ""; }; 124 | 49760BF0246D1F2700FEFD61 /* RowDestinationTitle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowDestinationTitle.swift; sourceTree = ""; }; 125 | 49760BF4246D1F3100FEFD61 /* HeaderHeadline2VM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderHeadline2VM.swift; sourceTree = ""; }; 126 | 49760BF5246D1F3100FEFD61 /* HeaderHeadline2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderHeadline2.swift; sourceTree = ""; }; 127 | 49760BF8246D1FAD00FEFD61 /* RowDestinationTitle.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RowDestinationTitle.xib; sourceTree = ""; }; 128 | 49760BFA246D2A0F00FEFD61 /* DestinationVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestinationVM.swift; sourceTree = ""; }; 129 | 49760BFD246D2C4F00FEFD61 /* RowText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowText.swift; sourceTree = ""; }; 130 | 49760BFE246D2C4F00FEFD61 /* RowTextVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowTextVM.swift; sourceTree = ""; }; 131 | 49760C02246D2E1F00FEFD61 /* CardPhotoThumbnail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardPhotoThumbnail.swift; sourceTree = ""; }; 132 | 49760C03246D2E1F00FEFD61 /* CardPhotoThumbnailVM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardPhotoThumbnailVM.swift; sourceTree = ""; }; 133 | 4C0087911647C97715E4AAE2 /* Pods-DesignSystemExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DesignSystemExample.debug.xcconfig"; path = "Target Support Files/Pods-DesignSystemExample/Pods-DesignSystemExample.debug.xcconfig"; sourceTree = ""; }; 134 | 57CC472D17DA59D0542A9685 /* Pods_DesignSystemExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DesignSystemExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 135 | 59108EA44C86F3235B966D8B /* BaseMagazineLayoutVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseMagazineLayoutVC.swift; sourceTree = ""; }; 136 | 5A1737C250A31319ABC50B29 /* FlowStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowStep.swift; sourceTree = ""; }; 137 | 65CC62DBC6583658B81FBD3D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 138 | 9774B0C6FB809C81934FD6D6 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 139 | A9839CA0B4CB5CDC640AEF89 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 140 | F9223680A65A94EEE31B7939 /* AppFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppFlow.swift; sourceTree = ""; }; 141 | /* End PBXFileReference section */ 142 | 143 | /* Begin PBXFrameworksBuildPhase section */ 144 | 1E853E856FC2B958D2D76620 /* Frameworks */ = { 145 | isa = PBXFrameworksBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | 9CCE1AC67533E7103F9F7192 /* Frameworks */ = { 152 | isa = PBXFrameworksBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | DB28D28E89BDF6803F9624F0 /* Pods_DesignSystemExample.framework in Frameworks */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXFrameworksBuildPhase section */ 160 | 161 | /* Begin PBXGroup section */ 162 | 0BE045A96384E8975F68E669 /* Products */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | 32B94D0248D350885B40EACE /* DesignSystemExample.app */, 166 | 24985D79969B12C8E94D111C /* DesignSystemExampleTests.xctest */, 167 | ); 168 | name = Products; 169 | sourceTree = ""; 170 | }; 171 | 1CC18408866C3365AF202A8D /* Project */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | D7678692E5333322D212C7E9 /* Classes */, 175 | D31E292452D236EDC5C2A72A /* Resources */, 176 | 65CC62DBC6583658B81FBD3D /* Info.plist */, 177 | ); 178 | name = Project; 179 | sourceTree = ""; 180 | }; 181 | 20D19F2F83F64AD3C95A63CB /* Screen */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 383D08CC216E24568F227648 /* Screen.swift */, 185 | ); 186 | path = Screen; 187 | sourceTree = ""; 188 | }; 189 | 3DC54CF785048977AE1386F1 /* UI */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 49760BE4246C44AB00FEFD61 /* Page */, 193 | 49760BBA246BCBC800FEFD61 /* Explore */, 194 | 49760BA424699AEC00FEFD61 /* Utils */, 195 | 7677C6032022D8D50F22077E /* BaseMagazineLayout */, 196 | 6FAACCC9C44D6226C0C4EAA8 /* DesignSystem */, 197 | 5643B195762F1BDBE100ACB9 /* Flow */, 198 | ); 199 | path = UI; 200 | sourceTree = ""; 201 | }; 202 | 3EC82ADD63307EAC9C5008FC /* Pods */ = { 203 | isa = PBXGroup; 204 | children = ( 205 | 4C0087911647C97715E4AAE2 /* Pods-DesignSystemExample.debug.xcconfig */, 206 | 2FCEC3565E97C3F5B74EA79F /* Pods-DesignSystemExample.release.xcconfig */, 207 | ); 208 | path = Pods; 209 | sourceTree = ""; 210 | }; 211 | 49760BA424699AEC00FEFD61 /* Utils */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | 49760BA524699AFF00FEFD61 /* Reusable.swift */, 215 | 4929660E2473B88A0061C94E /* RxUtils.swift */, 216 | ); 217 | path = Utils; 218 | sourceTree = ""; 219 | }; 220 | 49760BA7246AC08100FEFD61 /* Rows */ = { 221 | isa = PBXGroup; 222 | children = ( 223 | 49760BFC246D2C4F00FEFD61 /* RowText */, 224 | 49760BEE246D1F2700FEFD61 /* RowDestinationTitle */, 225 | 49760BDD246C312700FEFD61 /* RowFlightInfo */, 226 | 49760BCC246BEB5000FEFD61 /* RowHorizontalCardsCollection */, 227 | 49760BC5246BD5D900FEFD61 /* RowCaption */, 228 | 49760BB5246B0B3900FEFD61 /* RowHeadline1 */, 229 | ); 230 | path = Rows; 231 | sourceTree = ""; 232 | }; 233 | 49760BA8246AC08B00FEFD61 /* Cards */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | 49760C01246D2E1F00FEFD61 /* CardPhotoThumbnail */, 237 | 49760BD1246BEF3A00FEFD61 /* CardDestination */, 238 | ); 239 | path = Cards; 240 | sourceTree = ""; 241 | }; 242 | 49760BB5246B0B3900FEFD61 /* RowHeadline1 */ = { 243 | isa = PBXGroup; 244 | children = ( 245 | 49760BB6246B0B3900FEFD61 /* RowHeadline1VM.swift */, 246 | 49760BB7246B0B3900FEFD61 /* RowHeadline1.swift */, 247 | ); 248 | path = RowHeadline1; 249 | sourceTree = ""; 250 | }; 251 | 49760BBA246BCBC800FEFD61 /* Explore */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 49760BBB246BCBE100FEFD61 /* ExploreVM.swift */, 255 | ); 256 | path = Explore; 257 | sourceTree = ""; 258 | }; 259 | 49760BBF246BCF2500FEFD61 /* Typography */ = { 260 | isa = PBXGroup; 261 | children = ( 262 | 49760BC0246BCF4700FEFD61 /* Typography.swift */, 263 | ); 264 | path = Typography; 265 | sourceTree = ""; 266 | }; 267 | 49760BC2246BD11D00FEFD61 /* Colors */ = { 268 | isa = PBXGroup; 269 | children = ( 270 | 49760BC3246BD13000FEFD61 /* UIColor+Styles.swift */, 271 | ); 272 | path = Colors; 273 | sourceTree = ""; 274 | }; 275 | 49760BC5246BD5D900FEFD61 /* RowCaption */ = { 276 | isa = PBXGroup; 277 | children = ( 278 | 49760BC6246BD5D900FEFD61 /* RowCaption.swift */, 279 | 49760BC7246BD5D900FEFD61 /* RowCaptionVM.swift */, 280 | ); 281 | path = RowCaption; 282 | sourceTree = ""; 283 | }; 284 | 49760BCC246BEB5000FEFD61 /* RowHorizontalCardsCollection */ = { 285 | isa = PBXGroup; 286 | children = ( 287 | 49760BCE246BEB6400FEFD61 /* CardsHorizontalRow.swift */, 288 | 49760BCD246BEB6400FEFD61 /* CardsHorizontalRowVM.swift */, 289 | ); 290 | path = RowHorizontalCardsCollection; 291 | sourceTree = ""; 292 | }; 293 | 49760BD1246BEF3A00FEFD61 /* CardDestination */ = { 294 | isa = PBXGroup; 295 | children = ( 296 | 49760BD2246BEF3A00FEFD61 /* CardDestination.swift */, 297 | 49760BD3246BEF3A00FEFD61 /* CardDestinationVM.swift */, 298 | ); 299 | path = CardDestination; 300 | sourceTree = ""; 301 | }; 302 | 49760BD6246C261F00FEFD61 /* Headers */ = { 303 | isa = PBXGroup; 304 | children = ( 305 | 49760BF3246D1F3100FEFD61 /* Headline2 */, 306 | 49760BE7246C458D00FEFD61 /* Destination */, 307 | 49760BD7246C261F00FEFD61 /* SectionTitle */, 308 | ); 309 | path = Headers; 310 | sourceTree = ""; 311 | }; 312 | 49760BD7246C261F00FEFD61 /* SectionTitle */ = { 313 | isa = PBXGroup; 314 | children = ( 315 | 49760BD8246C261F00FEFD61 /* HeaderSectionTitleVM.swift */, 316 | 49760BD9246C261F00FEFD61 /* HeaderSectionTitle.swift */, 317 | ); 318 | path = SectionTitle; 319 | sourceTree = ""; 320 | }; 321 | 49760BDD246C312700FEFD61 /* RowFlightInfo */ = { 322 | isa = PBXGroup; 323 | children = ( 324 | 49760BDE246C312700FEFD61 /* RowFlightInfo.swift */, 325 | 49760BDF246C312700FEFD61 /* RowFlightInfoVM.swift */, 326 | 49760BE2246C31C200FEFD61 /* RowFlightInfo.xib */, 327 | ); 328 | path = RowFlightInfo; 329 | sourceTree = ""; 330 | }; 331 | 49760BE4246C44AB00FEFD61 /* Page */ = { 332 | isa = PBXGroup; 333 | children = ( 334 | 49760BE5246C44C800FEFD61 /* DestinationVC.swift */, 335 | 49760BFA246D2A0F00FEFD61 /* DestinationVM.swift */, 336 | ); 337 | path = Page; 338 | sourceTree = ""; 339 | }; 340 | 49760BE7246C458D00FEFD61 /* Destination */ = { 341 | isa = PBXGroup; 342 | children = ( 343 | 49760BE8246C45BD00FEFD61 /* HeaderDestination.swift */, 344 | 49760BEA246C45D500FEFD61 /* HeaderDestination.xib */, 345 | ); 346 | path = Destination; 347 | sourceTree = ""; 348 | }; 349 | 49760BEE246D1F2700FEFD61 /* RowDestinationTitle */ = { 350 | isa = PBXGroup; 351 | children = ( 352 | 49760BEF246D1F2700FEFD61 /* RowDestinationTitleVM.swift */, 353 | 49760BF0246D1F2700FEFD61 /* RowDestinationTitle.swift */, 354 | 49760BF8246D1FAD00FEFD61 /* RowDestinationTitle.xib */, 355 | ); 356 | path = RowDestinationTitle; 357 | sourceTree = ""; 358 | }; 359 | 49760BF3246D1F3100FEFD61 /* Headline2 */ = { 360 | isa = PBXGroup; 361 | children = ( 362 | 49760BF4246D1F3100FEFD61 /* HeaderHeadline2VM.swift */, 363 | 49760BF5246D1F3100FEFD61 /* HeaderHeadline2.swift */, 364 | ); 365 | path = Headline2; 366 | sourceTree = ""; 367 | }; 368 | 49760BFC246D2C4F00FEFD61 /* RowText */ = { 369 | isa = PBXGroup; 370 | children = ( 371 | 49760BFD246D2C4F00FEFD61 /* RowText.swift */, 372 | 49760BFE246D2C4F00FEFD61 /* RowTextVM.swift */, 373 | ); 374 | path = RowText; 375 | sourceTree = ""; 376 | }; 377 | 49760C01246D2E1F00FEFD61 /* CardPhotoThumbnail */ = { 378 | isa = PBXGroup; 379 | children = ( 380 | 49760C02246D2E1F00FEFD61 /* CardPhotoThumbnail.swift */, 381 | 49760C03246D2E1F00FEFD61 /* CardPhotoThumbnailVM.swift */, 382 | ); 383 | path = CardPhotoThumbnail; 384 | sourceTree = ""; 385 | }; 386 | 5643B195762F1BDBE100ACB9 /* Flow */ = { 387 | isa = PBXGroup; 388 | children = ( 389 | F9223680A65A94EEE31B7939 /* AppFlow.swift */, 390 | 5A1737C250A31319ABC50B29 /* FlowStep.swift */, 391 | 49760BBD246BCDA300FEFD61 /* ExploreFlow.swift */, 392 | ); 393 | path = Flow; 394 | sourceTree = ""; 395 | }; 396 | 5FF1DECDD33A53D1271E907B /* Localization */ = { 397 | isa = PBXGroup; 398 | children = ( 399 | 2D912EEB6348114B3A4FF1B8 /* Localizable.strings */, 400 | ); 401 | path = Localization; 402 | sourceTree = ""; 403 | }; 404 | 6FAACCC9C44D6226C0C4EAA8 /* DesignSystem */ = { 405 | isa = PBXGroup; 406 | children = ( 407 | 49760BD6246C261F00FEFD61 /* Headers */, 408 | 49760BC2246BD11D00FEFD61 /* Colors */, 409 | 49760BBF246BCF2500FEFD61 /* Typography */, 410 | 49760BA8246AC08B00FEFD61 /* Cards */, 411 | 49760BA7246AC08100FEFD61 /* Rows */, 412 | ); 413 | path = DesignSystem; 414 | sourceTree = ""; 415 | }; 416 | 73CCAF92C85EBD5B65527997 /* Assets */ = { 417 | isa = PBXGroup; 418 | children = ( 419 | 37375CAB15538E0540D15D45 /* Icons.xcassets */, 420 | ); 421 | path = Assets; 422 | sourceTree = ""; 423 | }; 424 | 74A9F14BA863A7DE1AE78449 /* Frameworks */ = { 425 | isa = PBXGroup; 426 | children = ( 427 | 57CC472D17DA59D0542A9685 /* Pods_DesignSystemExample.framework */, 428 | ); 429 | name = Frameworks; 430 | sourceTree = ""; 431 | }; 432 | 7677C6032022D8D50F22077E /* BaseMagazineLayout */ = { 433 | isa = PBXGroup; 434 | children = ( 435 | E3F789ECB349C8AA321D3778 /* CellsRegistrator */, 436 | BAC5F2858BE18795906237E3 /* Data */, 437 | DA7D6C04B66C34CB596E5094 /* Protocols */, 438 | 20D19F2F83F64AD3C95A63CB /* Screen */, 439 | 59108EA44C86F3235B966D8B /* BaseMagazineLayoutVC.swift */, 440 | 1F1DDB77D41F8E5654210256 /* CellConfigurators.swift */, 441 | ); 442 | path = BaseMagazineLayout; 443 | sourceTree = ""; 444 | }; 445 | AD0B9322C9F7D2F46AF481A8 = { 446 | isa = PBXGroup; 447 | children = ( 448 | 1CC18408866C3365AF202A8D /* Project */, 449 | 74A9F14BA863A7DE1AE78449 /* Frameworks */, 450 | 0BE045A96384E8975F68E669 /* Products */, 451 | 3EC82ADD63307EAC9C5008FC /* Pods */, 452 | ); 453 | sourceTree = ""; 454 | }; 455 | BAC5F2858BE18795906237E3 /* Data */ = { 456 | isa = PBXGroup; 457 | children = ( 458 | 24CE7E516BA1C742535515A8 /* MagazineLayoutSection.swift */, 459 | ); 460 | path = Data; 461 | sourceTree = ""; 462 | }; 463 | D31E292452D236EDC5C2A72A /* Resources */ = { 464 | isa = PBXGroup; 465 | children = ( 466 | 73CCAF92C85EBD5B65527997 /* Assets */, 467 | 5FF1DECDD33A53D1271E907B /* Localization */, 468 | E84E2F8C8FE2B6C6AEADF906 /* StoryBoards */, 469 | ); 470 | path = Resources; 471 | sourceTree = ""; 472 | }; 473 | D7678692E5333322D212C7E9 /* Classes */ = { 474 | isa = PBXGroup; 475 | children = ( 476 | 3DC54CF785048977AE1386F1 /* UI */, 477 | A9839CA0B4CB5CDC640AEF89 /* AppDelegate.swift */, 478 | ); 479 | path = Classes; 480 | sourceTree = ""; 481 | }; 482 | DA7D6C04B66C34CB596E5094 /* Protocols */ = { 483 | isa = PBXGroup; 484 | children = ( 485 | 1F076547F3877FA786B0B88C /* StepSupportable.swift */, 486 | ); 487 | path = Protocols; 488 | sourceTree = ""; 489 | }; 490 | E3F789ECB349C8AA321D3778 /* CellsRegistrator */ = { 491 | isa = PBXGroup; 492 | children = ( 493 | 46377B511079178264596B00 /* CollectionViewCellsRegistrator.swift */, 494 | ); 495 | path = CellsRegistrator; 496 | sourceTree = ""; 497 | }; 498 | E84E2F8C8FE2B6C6AEADF906 /* StoryBoards */ = { 499 | isa = PBXGroup; 500 | children = ( 501 | 9774B0C6FB809C81934FD6D6 /* LaunchScreen.storyboard */, 502 | 36E32FD601B4C8B3204C4B48 /* Main.storyboard */, 503 | ); 504 | path = StoryBoards; 505 | sourceTree = ""; 506 | }; 507 | /* End PBXGroup section */ 508 | 509 | /* Begin PBXNativeTarget section */ 510 | E01795BE645342C12AE9CB31 /* DesignSystemExampleTests */ = { 511 | isa = PBXNativeTarget; 512 | buildConfigurationList = 647CA8E2D335B2C7C0285617 /* Build configuration list for PBXNativeTarget "DesignSystemExampleTests" */; 513 | buildPhases = ( 514 | B7E5C440A198B614CBBA2CC5 /* Sources */, 515 | 9DF3A7780729827B84B22AB3 /* Resources */, 516 | 89EFD6D82D228912602DFEC9 /* Embed Precompiled Frameworks */, 517 | C96A27622B98ED2B9E6CBACC /* Embed Frameworks */, 518 | 1E853E856FC2B958D2D76620 /* Frameworks */, 519 | ); 520 | buildRules = ( 521 | ); 522 | dependencies = ( 523 | BC2E789E792E46986BAA00BF /* PBXTargetDependency */, 524 | ); 525 | name = DesignSystemExampleTests; 526 | productName = DesignSystemExampleTests; 527 | productReference = 24985D79969B12C8E94D111C /* DesignSystemExampleTests.xctest */; 528 | productType = "com.apple.product-type.bundle.unit-test"; 529 | }; 530 | EADCFA617F448DCA4A19BD95 /* DesignSystemExample */ = { 531 | isa = PBXNativeTarget; 532 | buildConfigurationList = D3C020869D06D93ECE854F51 /* Build configuration list for PBXNativeTarget "DesignSystemExample" */; 533 | buildPhases = ( 534 | 82AEBCB7DCCFE60686D856E2 /* [CP] Check Pods Manifest.lock */, 535 | D209C31BA3AF09A54B380245 /* Sources */, 536 | FD3642F4DF967613E75BF204 /* Resources */, 537 | 82AD25BE26A0A246DC3FFDC0 /* Embed Precompiled Frameworks */, 538 | 778909214512A9D9E3353F33 /* Embed Frameworks */, 539 | 9CCE1AC67533E7103F9F7192 /* Frameworks */, 540 | 4AA33020AE3D3BC0CF0A5891 /* [CP] Embed Pods Frameworks */, 541 | ); 542 | buildRules = ( 543 | ); 544 | dependencies = ( 545 | ); 546 | name = DesignSystemExample; 547 | productName = DesignSystemExample; 548 | productReference = 32B94D0248D350885B40EACE /* DesignSystemExample.app */; 549 | productType = "com.apple.product-type.application"; 550 | }; 551 | /* End PBXNativeTarget section */ 552 | 553 | /* Begin PBXProject section */ 554 | 15C6769C3FF9813D7AA4DC60 /* Project object */ = { 555 | isa = PBXProject; 556 | attributes = { 557 | ORGANIZATIONNAME = "Chili Labs"; 558 | TargetAttributes = { 559 | E01795BE645342C12AE9CB31 = { 560 | TestTargetID = EADCFA617F448DCA4A19BD95; 561 | }; 562 | }; 563 | }; 564 | buildConfigurationList = 32E95210C8878BC2AF964F48 /* Build configuration list for PBXProject "DesignSystemExample" */; 565 | compatibilityVersion = "Xcode 9.3"; 566 | developmentRegion = en; 567 | hasScannedForEncodings = 0; 568 | knownRegions = ( 569 | Base, 570 | en, 571 | ); 572 | mainGroup = AD0B9322C9F7D2F46AF481A8; 573 | productRefGroup = 0BE045A96384E8975F68E669 /* Products */; 574 | projectDirPath = ""; 575 | projectRoot = ""; 576 | targets = ( 577 | EADCFA617F448DCA4A19BD95 /* DesignSystemExample */, 578 | E01795BE645342C12AE9CB31 /* DesignSystemExampleTests */, 579 | ); 580 | }; 581 | /* End PBXProject section */ 582 | 583 | /* Begin PBXResourcesBuildPhase section */ 584 | 9DF3A7780729827B84B22AB3 /* Resources */ = { 585 | isa = PBXResourcesBuildPhase; 586 | buildActionMask = 2147483647; 587 | files = ( 588 | ); 589 | runOnlyForDeploymentPostprocessing = 0; 590 | }; 591 | FD3642F4DF967613E75BF204 /* Resources */ = { 592 | isa = PBXResourcesBuildPhase; 593 | buildActionMask = 2147483647; 594 | files = ( 595 | 7FE0B7AB2105FF48BF2A460F /* Icons.xcassets in Resources */, 596 | 9986536FED1C215480292268 /* Localizable.strings in Resources */, 597 | D7ABC8DDF8AE396533866E45 /* LaunchScreen.storyboard in Resources */, 598 | F2E98AA4069B277626889811 /* Main.storyboard in Resources */, 599 | 49760BE3246C31C200FEFD61 /* RowFlightInfo.xib in Resources */, 600 | 49760BEB246C45D500FEFD61 /* HeaderDestination.xib in Resources */, 601 | 49760BF9246D1FAD00FEFD61 /* RowDestinationTitle.xib in Resources */, 602 | ); 603 | runOnlyForDeploymentPostprocessing = 0; 604 | }; 605 | /* End PBXResourcesBuildPhase section */ 606 | 607 | /* Begin PBXShellScriptBuildPhase section */ 608 | 4AA33020AE3D3BC0CF0A5891 /* [CP] Embed Pods Frameworks */ = { 609 | isa = PBXShellScriptBuildPhase; 610 | buildActionMask = 2147483647; 611 | files = ( 612 | ); 613 | inputFileListPaths = ( 614 | "${PODS_ROOT}/Target Support Files/Pods-DesignSystemExample/Pods-DesignSystemExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", 615 | ); 616 | name = "[CP] Embed Pods Frameworks"; 617 | outputFileListPaths = ( 618 | "${PODS_ROOT}/Target Support Files/Pods-DesignSystemExample/Pods-DesignSystemExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", 619 | ); 620 | runOnlyForDeploymentPostprocessing = 0; 621 | shellPath = /bin/sh; 622 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DesignSystemExample/Pods-DesignSystemExample-frameworks.sh\"\n"; 623 | showEnvVarsInLog = 0; 624 | }; 625 | 82AD25BE26A0A246DC3FFDC0 /* Embed Precompiled Frameworks */ = { 626 | isa = PBXShellScriptBuildPhase; 627 | buildActionMask = 2147483647; 628 | files = ( 629 | ); 630 | inputPaths = ( 631 | ); 632 | name = "Embed Precompiled Frameworks"; 633 | outputPaths = ( 634 | ); 635 | runOnlyForDeploymentPostprocessing = 0; 636 | shellPath = /bin/sh; 637 | shellScript = "echo \"Skipping, nothing to be embedded.\""; 638 | }; 639 | 82AEBCB7DCCFE60686D856E2 /* [CP] Check Pods Manifest.lock */ = { 640 | isa = PBXShellScriptBuildPhase; 641 | buildActionMask = 2147483647; 642 | files = ( 643 | ); 644 | inputFileListPaths = ( 645 | ); 646 | inputPaths = ( 647 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 648 | "${PODS_ROOT}/Manifest.lock", 649 | ); 650 | name = "[CP] Check Pods Manifest.lock"; 651 | outputFileListPaths = ( 652 | ); 653 | outputPaths = ( 654 | "$(DERIVED_FILE_DIR)/Pods-DesignSystemExample-checkManifestLockResult.txt", 655 | ); 656 | runOnlyForDeploymentPostprocessing = 0; 657 | shellPath = /bin/sh; 658 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 659 | showEnvVarsInLog = 0; 660 | }; 661 | 89EFD6D82D228912602DFEC9 /* Embed Precompiled Frameworks */ = { 662 | isa = PBXShellScriptBuildPhase; 663 | buildActionMask = 2147483647; 664 | files = ( 665 | ); 666 | inputPaths = ( 667 | ); 668 | name = "Embed Precompiled Frameworks"; 669 | outputPaths = ( 670 | ); 671 | runOnlyForDeploymentPostprocessing = 0; 672 | shellPath = /bin/sh; 673 | shellScript = "echo \"Skipping, nothing to be embedded.\""; 674 | }; 675 | /* End PBXShellScriptBuildPhase section */ 676 | 677 | /* Begin PBXSourcesBuildPhase section */ 678 | B7E5C440A198B614CBBA2CC5 /* Sources */ = { 679 | isa = PBXSourcesBuildPhase; 680 | buildActionMask = 2147483647; 681 | files = ( 682 | ); 683 | runOnlyForDeploymentPostprocessing = 0; 684 | }; 685 | D209C31BA3AF09A54B380245 /* Sources */ = { 686 | isa = PBXSourcesBuildPhase; 687 | buildActionMask = 2147483647; 688 | files = ( 689 | 49760BB8246B0B3900FEFD61 /* RowHeadline1VM.swift in Sources */, 690 | 49760BBE246BCDA300FEFD61 /* ExploreFlow.swift in Sources */, 691 | 95DD07E8976969469D3191FA /* AppDelegate.swift in Sources */, 692 | 49760C05246D2E2000FEFD61 /* CardPhotoThumbnailVM.swift in Sources */, 693 | 49760BA624699AFF00FEFD61 /* Reusable.swift in Sources */, 694 | ABB6B97D199EC99BF1B1867B /* BaseMagazineLayoutVC.swift in Sources */, 695 | 49760BF7246D1F3100FEFD61 /* HeaderHeadline2.swift in Sources */, 696 | 49760BC8246BD5D900FEFD61 /* RowCaption.swift in Sources */, 697 | 49760BF1246D1F2700FEFD61 /* RowDestinationTitleVM.swift in Sources */, 698 | 04D3491EBF034C557B0624BD /* CellConfigurators.swift in Sources */, 699 | 49760C00246D2C4F00FEFD61 /* RowTextVM.swift in Sources */, 700 | 49760BD4246BEF3B00FEFD61 /* CardDestination.swift in Sources */, 701 | 49760C04246D2E2000FEFD61 /* CardPhotoThumbnail.swift in Sources */, 702 | AF3EFA21160AF3257FF42D31 /* CollectionViewCellsRegistrator.swift in Sources */, 703 | 49760BBC246BCBE100FEFD61 /* ExploreVM.swift in Sources */, 704 | 839A9D96EB313DD94FA58E22 /* MagazineLayoutSection.swift in Sources */, 705 | 49760BFB246D2A0F00FEFD61 /* DestinationVM.swift in Sources */, 706 | 49760BE1246C312700FEFD61 /* RowFlightInfoVM.swift in Sources */, 707 | C7113BB953D5AA27AB0C3CD1 /* StepSupportable.swift in Sources */, 708 | 49760BC1246BCF4700FEFD61 /* Typography.swift in Sources */, 709 | 49760BC9246BD5D900FEFD61 /* RowCaptionVM.swift in Sources */, 710 | 49760BC4246BD13000FEFD61 /* UIColor+Styles.swift in Sources */, 711 | 49760BE0246C312700FEFD61 /* RowFlightInfo.swift in Sources */, 712 | 49760BD0246BEB6400FEFD61 /* CardsHorizontalRow.swift in Sources */, 713 | F88F21E51666FA41FF4A275F /* Screen.swift in Sources */, 714 | 57025306DF211B937B09467A /* AppFlow.swift in Sources */, 715 | 49760BB9246B0B3900FEFD61 /* RowHeadline1.swift in Sources */, 716 | 49760BE9246C45BD00FEFD61 /* HeaderDestination.swift in Sources */, 717 | 49760BDB246C261F00FEFD61 /* HeaderSectionTitle.swift in Sources */, 718 | 49760BCF246BEB6400FEFD61 /* CardsHorizontalRowVM.swift in Sources */, 719 | 49760BDA246C261F00FEFD61 /* HeaderSectionTitleVM.swift in Sources */, 720 | 4929660F2473B88A0061C94E /* RxUtils.swift in Sources */, 721 | 49760BF2246D1F2700FEFD61 /* RowDestinationTitle.swift in Sources */, 722 | 7836C978DD3EF1B13922EA51 /* FlowStep.swift in Sources */, 723 | 49760BD5246BEF3B00FEFD61 /* CardDestinationVM.swift in Sources */, 724 | 49760BFF246D2C4F00FEFD61 /* RowText.swift in Sources */, 725 | 49760BE6246C44C800FEFD61 /* DestinationVC.swift in Sources */, 726 | 49760BF6246D1F3100FEFD61 /* HeaderHeadline2VM.swift in Sources */, 727 | ); 728 | runOnlyForDeploymentPostprocessing = 0; 729 | }; 730 | /* End PBXSourcesBuildPhase section */ 731 | 732 | /* Begin PBXTargetDependency section */ 733 | BC2E789E792E46986BAA00BF /* PBXTargetDependency */ = { 734 | isa = PBXTargetDependency; 735 | name = DesignSystemExample; 736 | target = EADCFA617F448DCA4A19BD95 /* DesignSystemExample */; 737 | targetProxy = 216F8559619519337020F075 /* PBXContainerItemProxy */; 738 | }; 739 | /* End PBXTargetDependency section */ 740 | 741 | /* Begin XCBuildConfiguration section */ 742 | 4CF0B1150186F371010C1E6B /* Release */ = { 743 | isa = XCBuildConfiguration; 744 | buildSettings = { 745 | BUNDLE_LOADER = "$(TEST_HOST)"; 746 | CODE_SIGN_IDENTITY = "iPhone Developer"; 747 | INFOPLIST_FILE = Info.plist; 748 | LD_RUNPATH_SEARCH_PATHS = ( 749 | "$(inherited)", 750 | "@executable_path/Frameworks", 751 | "@loader_path/Frameworks", 752 | ); 753 | PRODUCT_BUNDLE_IDENTIFIER = lv.chi.DesignSystemExampleTests; 754 | PRODUCT_NAME = DesignSystemExampleTests; 755 | SDKROOT = iphoneos; 756 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 757 | SWIFT_COMPILATION_MODE = wholemodule; 758 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 759 | SWIFT_VERSION = 5.2; 760 | TARGETED_DEVICE_FAMILY = "1,2"; 761 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DesignSystemExample.app/DesignSystemExample"; 762 | TEST_TARGET_NAME = DesignSystemExample; 763 | }; 764 | name = Release; 765 | }; 766 | 5C5AB5C10BB4B60AA517E0F7 /* Debug */ = { 767 | isa = XCBuildConfiguration; 768 | baseConfigurationReference = 4C0087911647C97715E4AAE2 /* Pods-DesignSystemExample.debug.xcconfig */; 769 | buildSettings = { 770 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 771 | CODE_SIGN_IDENTITY = "iPhone Developer"; 772 | DEVELOPMENT_TEAM = 4J5NY3YD66; 773 | ENABLE_PREVIEWS = YES; 774 | INFOPLIST_FILE = Info.plist; 775 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 776 | LD_RUNPATH_SEARCH_PATHS = ( 777 | "$(inherited)", 778 | "@executable_path/Frameworks", 779 | ); 780 | PRODUCT_BUNDLE_IDENTIFIER = lv.chi.DesignSystemExample; 781 | PRODUCT_NAME = DesignSystemExample; 782 | SDKROOT = iphoneos; 783 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 784 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 785 | SWIFT_COMPILATION_MODE = singlefile; 786 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 787 | SWIFT_VERSION = 5.2; 788 | TARGETED_DEVICE_FAMILY = 1; 789 | }; 790 | name = Debug; 791 | }; 792 | A7955594C17055C6FDC2AA11 /* Debug */ = { 793 | isa = XCBuildConfiguration; 794 | buildSettings = { 795 | ALWAYS_SEARCH_USER_PATHS = NO; 796 | CLANG_ANALYZER_NONNULL = YES; 797 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 798 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 799 | CLANG_CXX_LIBRARY = "libc++"; 800 | CLANG_ENABLE_MODULES = YES; 801 | CLANG_ENABLE_OBJC_ARC = YES; 802 | CLANG_ENABLE_OBJC_WEAK = YES; 803 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 804 | CLANG_WARN_BOOL_CONVERSION = YES; 805 | CLANG_WARN_COMMA = YES; 806 | CLANG_WARN_CONSTANT_CONVERSION = YES; 807 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 808 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 809 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 810 | CLANG_WARN_EMPTY_BODY = YES; 811 | CLANG_WARN_ENUM_CONVERSION = YES; 812 | CLANG_WARN_INFINITE_RECURSION = YES; 813 | CLANG_WARN_INT_CONVERSION = YES; 814 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 815 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 816 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 817 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 818 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 819 | CLANG_WARN_STRICT_PROTOTYPES = YES; 820 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 821 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 822 | CLANG_WARN_UNREACHABLE_CODE = YES; 823 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 824 | COPY_PHASE_STRIP = NO; 825 | DEBUG_INFORMATION_FORMAT = dwarf; 826 | ENABLE_STRICT_OBJC_MSGSEND = YES; 827 | ENABLE_TESTABILITY = YES; 828 | GCC_C_LANGUAGE_STANDARD = gnu11; 829 | GCC_DYNAMIC_NO_PIC = NO; 830 | GCC_NO_COMMON_BLOCKS = YES; 831 | GCC_OPTIMIZATION_LEVEL = 0; 832 | GCC_PREPROCESSOR_DEFINITIONS = ( 833 | "DEBUG=1", 834 | "$(inherited)", 835 | ); 836 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 837 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 838 | GCC_WARN_UNDECLARED_SELECTOR = YES; 839 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 840 | GCC_WARN_UNUSED_FUNCTION = YES; 841 | GCC_WARN_UNUSED_VARIABLE = YES; 842 | MTL_ENABLE_DEBUG_INFO = YES; 843 | ONLY_ACTIVE_ARCH = YES; 844 | PRODUCT_NAME = "$(TARGET_NAME)"; 845 | }; 846 | name = Debug; 847 | }; 848 | C9ADDDE3B4E52DB5E1DF30EE /* Release */ = { 849 | isa = XCBuildConfiguration; 850 | baseConfigurationReference = 2FCEC3565E97C3F5B74EA79F /* Pods-DesignSystemExample.release.xcconfig */; 851 | buildSettings = { 852 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 853 | CODE_SIGN_IDENTITY = "iPhone Developer"; 854 | DEVELOPMENT_TEAM = 4J5NY3YD66; 855 | ENABLE_PREVIEWS = YES; 856 | INFOPLIST_FILE = Info.plist; 857 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 858 | LD_RUNPATH_SEARCH_PATHS = ( 859 | "$(inherited)", 860 | "@executable_path/Frameworks", 861 | ); 862 | PRODUCT_BUNDLE_IDENTIFIER = lv.chi.DesignSystemExample; 863 | PRODUCT_NAME = DesignSystemExample; 864 | SDKROOT = iphoneos; 865 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 866 | SWIFT_COMPILATION_MODE = wholemodule; 867 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 868 | SWIFT_VERSION = 5.2; 869 | TARGETED_DEVICE_FAMILY = 1; 870 | }; 871 | name = Release; 872 | }; 873 | E850E2DC23D47C4B58DA1E3C /* Release */ = { 874 | isa = XCBuildConfiguration; 875 | buildSettings = { 876 | ALWAYS_SEARCH_USER_PATHS = NO; 877 | CLANG_ANALYZER_NONNULL = YES; 878 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 879 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 880 | CLANG_CXX_LIBRARY = "libc++"; 881 | CLANG_ENABLE_MODULES = YES; 882 | CLANG_ENABLE_OBJC_ARC = YES; 883 | CLANG_ENABLE_OBJC_WEAK = YES; 884 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 885 | CLANG_WARN_BOOL_CONVERSION = YES; 886 | CLANG_WARN_COMMA = YES; 887 | CLANG_WARN_CONSTANT_CONVERSION = YES; 888 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 889 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 890 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 891 | CLANG_WARN_EMPTY_BODY = YES; 892 | CLANG_WARN_ENUM_CONVERSION = YES; 893 | CLANG_WARN_INFINITE_RECURSION = YES; 894 | CLANG_WARN_INT_CONVERSION = YES; 895 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 896 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 897 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 898 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 899 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 900 | CLANG_WARN_STRICT_PROTOTYPES = YES; 901 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 902 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 903 | CLANG_WARN_UNREACHABLE_CODE = YES; 904 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 905 | COPY_PHASE_STRIP = NO; 906 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 907 | ENABLE_NS_ASSERTIONS = NO; 908 | ENABLE_STRICT_OBJC_MSGSEND = YES; 909 | GCC_C_LANGUAGE_STANDARD = gnu11; 910 | GCC_NO_COMMON_BLOCKS = YES; 911 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 912 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 913 | GCC_WARN_UNDECLARED_SELECTOR = YES; 914 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 915 | GCC_WARN_UNUSED_FUNCTION = YES; 916 | GCC_WARN_UNUSED_VARIABLE = YES; 917 | MTL_ENABLE_DEBUG_INFO = NO; 918 | PRODUCT_NAME = "$(TARGET_NAME)"; 919 | VALIDATE_PRODUCT = YES; 920 | }; 921 | name = Release; 922 | }; 923 | FFC445AC18876D8F9E15B551 /* Debug */ = { 924 | isa = XCBuildConfiguration; 925 | buildSettings = { 926 | BUNDLE_LOADER = "$(TEST_HOST)"; 927 | CODE_SIGN_IDENTITY = "iPhone Developer"; 928 | INFOPLIST_FILE = Info.plist; 929 | LD_RUNPATH_SEARCH_PATHS = ( 930 | "$(inherited)", 931 | "@executable_path/Frameworks", 932 | "@loader_path/Frameworks", 933 | ); 934 | PRODUCT_BUNDLE_IDENTIFIER = lv.chi.DesignSystemExampleTests; 935 | PRODUCT_NAME = DesignSystemExampleTests; 936 | SDKROOT = iphoneos; 937 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; 938 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 939 | SWIFT_COMPILATION_MODE = singlefile; 940 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 941 | SWIFT_VERSION = 5.2; 942 | TARGETED_DEVICE_FAMILY = "1,2"; 943 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DesignSystemExample.app/DesignSystemExample"; 944 | TEST_TARGET_NAME = DesignSystemExample; 945 | }; 946 | name = Debug; 947 | }; 948 | /* End XCBuildConfiguration section */ 949 | 950 | /* Begin XCConfigurationList section */ 951 | 32E95210C8878BC2AF964F48 /* Build configuration list for PBXProject "DesignSystemExample" */ = { 952 | isa = XCConfigurationList; 953 | buildConfigurations = ( 954 | A7955594C17055C6FDC2AA11 /* Debug */, 955 | E850E2DC23D47C4B58DA1E3C /* Release */, 956 | ); 957 | defaultConfigurationIsVisible = 0; 958 | defaultConfigurationName = Release; 959 | }; 960 | 647CA8E2D335B2C7C0285617 /* Build configuration list for PBXNativeTarget "DesignSystemExampleTests" */ = { 961 | isa = XCConfigurationList; 962 | buildConfigurations = ( 963 | FFC445AC18876D8F9E15B551 /* Debug */, 964 | 4CF0B1150186F371010C1E6B /* Release */, 965 | ); 966 | defaultConfigurationIsVisible = 0; 967 | defaultConfigurationName = Release; 968 | }; 969 | D3C020869D06D93ECE854F51 /* Build configuration list for PBXNativeTarget "DesignSystemExample" */ = { 970 | isa = XCConfigurationList; 971 | buildConfigurations = ( 972 | 5C5AB5C10BB4B60AA517E0F7 /* Debug */, 973 | C9ADDDE3B4E52DB5E1DF30EE /* Release */, 974 | ); 975 | defaultConfigurationIsVisible = 0; 976 | defaultConfigurationName = Release; 977 | }; 978 | /* End XCConfigurationList section */ 979 | }; 980 | rootObject = 15C6769C3FF9813D7AA4DC60 /* Project object */; 981 | } 982 | -------------------------------------------------------------------------------- /DesignSystemExample.xcodeproj/xcshareddata/xcschemes/DesignSystemExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UIStatusBarStyle 37 | UIStatusBarStyleDarkContent 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | UIUserInterfaceStyle 50 | Light 51 | UIViewControllerBasedStatusBarAppearance 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'git@github.com:CocoaPods/Specs.git' 2 | 3 | platform :ios, '12.0' 4 | 5 | inhibit_all_warnings! 6 | 7 | target 'DesignSystemExample' do 8 | use_frameworks! 9 | 10 | #Rx 11 | pod 'RxSwift', '~> 5.1' 12 | pod 'RxCocoa', '~> 5.1' 13 | pod 'RxFlow', '~> 2.8' 14 | 15 | #UI 16 | pod 'MagazineLayout', '~> 1.6' 17 | pod 'SnapKit', '~> 4.2' 18 | pod 'Kingfisher', '~> 5.1' 19 | pod 'MXParallaxHeader', '~> 1.1' 20 | 21 | #Typography 22 | pod 'BonMot', '~> 5.5' 23 | 24 | end 25 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BonMot (5.5.1) 3 | - Kingfisher (5.13.4): 4 | - Kingfisher/Core (= 5.13.4) 5 | - Kingfisher/Core (5.13.4) 6 | - MagazineLayout (1.6.0) 7 | - MXParallaxHeader (1.1.0) 8 | - RxCocoa (5.1.1): 9 | - RxRelay (~> 5) 10 | - RxSwift (~> 5) 11 | - RxFlow (2.8.0): 12 | - RxCocoa (>= 5.1.1) 13 | - RxSwift (>= 5.1.1) 14 | - RxRelay (5.1.1): 15 | - RxSwift (~> 5) 16 | - RxSwift (5.1.1) 17 | - SnapKit (4.2.0) 18 | 19 | DEPENDENCIES: 20 | - BonMot (~> 5.5) 21 | - Kingfisher (~> 5.1) 22 | - MagazineLayout (~> 1.6) 23 | - MXParallaxHeader (~> 1.1) 24 | - RxCocoa (~> 5.1) 25 | - RxFlow (~> 2.8) 26 | - RxSwift (~> 5.1) 27 | - SnapKit (~> 4.2) 28 | 29 | SPEC REPOS: 30 | https://github.com/CocoaPods/Specs.git: 31 | - BonMot 32 | - Kingfisher 33 | - MagazineLayout 34 | - MXParallaxHeader 35 | - RxCocoa 36 | - RxFlow 37 | - RxRelay 38 | - RxSwift 39 | - SnapKit 40 | 41 | SPEC CHECKSUMS: 42 | BonMot: 0d179476725af81f622a6d9f660f43048070016a 43 | Kingfisher: d2279a7abece3c7f25a80cd2b7f363ca5cf3f44c 44 | MagazineLayout: 3f6e9268fbdf6fe7519c630e53be5a05aede5957 45 | MXParallaxHeader: de3c867e10ba46e8f6e20c8ee1f2a910372b3b94 46 | RxCocoa: 32065309a38d29b5b0db858819b5bf9ef038b601 47 | RxFlow: 41c9d56e7611c6470d00febdfee08b63b0b018f8 48 | RxRelay: d77f7d771495f43c556cbc43eebd1bb54d01e8e9 49 | RxSwift: 81470a2074fa8780320ea5fe4102807cb7118178 50 | SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a 51 | 52 | PODFILE CHECKSUM: 39322496d0939952340fffbaa8773c5bcd897f8e 53 | 54 | COCOAPODS: 1.8.4 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS Design System Example 2 | An example project to show how design system components can be used in the project. 3 | 4 | Article - https://medium.com/chili-labs/implementing-design-system-components-on-ios-6afe873ea586 5 | 6 | 7 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon-ios-20@2x.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "icon-ios-20@3x.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "icon-ios-29@2x.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "icon-ios-29@3x.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "icon-ios-40@2x.png", 29 | "idiom" : "iphone", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "filename" : "icon-ios-40@3x.png", 35 | "idiom" : "iphone", 36 | "scale" : "3x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "icon-ios-60@2x.png", 41 | "idiom" : "iphone", 42 | "scale" : "2x", 43 | "size" : "60x60" 44 | }, 45 | { 46 | "filename" : "icon-ios-60@3x.png", 47 | "idiom" : "iphone", 48 | "scale" : "3x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "icon-ios-1024@1x.png", 53 | "idiom" : "ios-marketing", 54 | "scale" : "1x", 55 | "size" : "1024x1024" 56 | } 57 | ], 58 | "info" : { 59 | "author" : "xcode", 60 | "version" : 1 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-1024@1x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-20@2x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-20@3x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-29@2x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-29@3x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-40@2x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-40@3x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-60@2x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/AppIcon.appiconset/icon-ios-60@3x.png -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/destination.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "destination.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/destination.imageset/destination.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChiliLabs/ios_DesignSystemExample/868b07ed4562fe829fb3a2ab2582dfff352af3a7/Resources/Assets/Icons.xcassets/destination.imageset/destination.jpg -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/header_corner.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "header_corner.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/header_corner.imageset/header_corner.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << >> 5 | endobj 6 | 7 | 2 0 obj 8 | << /Length 3 0 R >> 9 | stream 10 | /DeviceRGB CS 11 | /DeviceRGB cs 12 | q 13 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm 14 | 1.000000 1.000000 1.000000 scn 15 | 0.000000 8.312809 m 16 | 0.000000 28.574585 16.425415 45.000000 36.687191 45.000000 c 17 | 45.000000 45.000000 l 18 | 45.000000 0.000000 l 19 | 0.000000 0.000000 l 20 | 0.000000 8.312809 l 21 | h 22 | f 23 | n 24 | Q 25 | 26 | endstream 27 | endobj 28 | 29 | 3 0 obj 30 | 291 31 | endobj 32 | 33 | 4 0 obj 34 | << /Annots [] 35 | /Type /Page 36 | /MediaBox [ 0.000000 0.000000 45.000000 45.000000 ] 37 | /Resources 1 0 R 38 | /Contents 2 0 R 39 | /Parent 5 0 R 40 | >> 41 | endobj 42 | 43 | 5 0 obj 44 | << /Kids [ 4 0 R ] 45 | /Count 1 46 | /Type /Pages 47 | >> 48 | endobj 49 | 50 | 6 0 obj 51 | << /Type /Catalog 52 | /Pages 5 0 R 53 | >> 54 | endobj 55 | 56 | xref 57 | 0 7 58 | 0000000000 65535 f 59 | 0000000010 00000 n 60 | 0000000034 00000 n 61 | 0000000381 00000 n 62 | 0000000403 00000 n 63 | 0000000576 00000 n 64 | 0000000650 00000 n 65 | trailer 66 | << /ID [ (some) (id) ] 67 | /Root 6 0 R 68 | /Size 7 69 | >> 70 | startxref 71 | 709 72 | %%EOF -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_flight_status.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ico_flight_status.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_flight_status.imageset/ico_flight_status.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << >> 5 | endobj 6 | 7 | 2 0 obj 8 | << /Length 3 0 R >> 9 | stream 10 | /DeviceRGB CS 11 | /DeviceRGB cs 12 | q 13 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm 14 | 1.000000 0.470238 0.000000 scn 15 | 10.995073 5.497535 m 16 | 10.995073 2.461329 8.533742 -0.000002 5.497537 -0.000002 c 17 | 2.461331 -0.000002 0.000000 2.461329 0.000000 5.497535 c 18 | 0.000000 8.533741 2.461331 10.995071 5.497537 10.995071 c 19 | 8.533742 10.995071 10.995073 8.533741 10.995073 5.497535 c 20 | h 21 | f 22 | n 23 | Q 24 | 25 | endstream 26 | endobj 27 | 28 | 3 0 obj 29 | 381 30 | endobj 31 | 32 | 4 0 obj 33 | << /Annots [] 34 | /Type /Page 35 | /MediaBox [ 0.000000 0.000000 10.995071 10.995071 ] 36 | /Resources 1 0 R 37 | /Contents 2 0 R 38 | /Parent 5 0 R 39 | >> 40 | endobj 41 | 42 | 5 0 obj 43 | << /Kids [ 4 0 R ] 44 | /Count 1 45 | /Type /Pages 46 | >> 47 | endobj 48 | 49 | 6 0 obj 50 | << /Type /Catalog 51 | /Pages 5 0 R 52 | >> 53 | endobj 54 | 55 | xref 56 | 0 7 57 | 0000000000 65535 f 58 | 0000000010 00000 n 59 | 0000000034 00000 n 60 | 0000000471 00000 n 61 | 0000000493 00000 n 62 | 0000000666 00000 n 63 | 0000000740 00000 n 64 | trailer 65 | << /ID [ (some) (id) ] 66 | /Root 6 0 R 67 | /Size 7 68 | >> 69 | startxref 70 | 799 71 | %%EOF -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_heart.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ico_heart.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_heart.imageset/ico_heart.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << >> 5 | endobj 6 | 7 | 2 0 obj 8 | << /Length 3 0 R >> 9 | stream 10 | /DeviceRGB CS 11 | /DeviceRGB cs 12 | q 13 | 1.000000 0.000000 -0.000000 1.000000 0.000000 1.834370 cm 14 | 1.000000 0.470238 0.000000 scn 15 | 16.364235 20.789410 m 16 | 14.400527 20.789410 12.515819 19.871731 11.285679 18.421570 c 17 | 10.055540 19.871731 8.170832 20.789410 6.207124 20.789410 c 18 | 2.731134 20.789410 0.000000 18.047701 0.000000 14.558252 c 19 | 0.000000 10.275747 3.837131 6.786298 9.649256 1.484148 c 20 | 11.285679 0.000000 l 21 | 12.922103 1.495478 l 22 | 18.734228 6.786298 22.571358 10.275747 22.571358 14.558252 c 23 | 22.571358 18.047701 19.840223 20.789410 16.364235 20.789410 c 24 | h 25 | 11.398537 3.172228 m 26 | 11.285679 3.058933 l 27 | 11.172822 3.172228 l 28 | 5.800838 8.055190 2.257136 11.284061 2.257136 14.558252 c 29 | 2.257136 16.824127 3.949988 18.523535 6.207124 18.523535 c 30 | 7.945118 18.523535 9.637970 17.401926 10.236111 15.849800 c 31 | 12.346533 15.849800 l 32 | 12.933388 17.401926 14.626241 18.523535 16.364235 18.523535 c 33 | 18.621370 18.523535 20.314222 16.824127 20.314222 14.558252 c 34 | 20.314222 11.284061 16.770519 8.055190 11.398537 3.172228 c 35 | h 36 | f 37 | n 38 | Q 39 | 40 | endstream 41 | endobj 42 | 43 | 3 0 obj 44 | 1000 45 | endobj 46 | 47 | 4 0 obj 48 | << /Annots [] 49 | /Type /Page 50 | /MediaBox [ 0.000000 0.000000 24.458130 24.458130 ] 51 | /Resources 1 0 R 52 | /Contents 2 0 R 53 | /Parent 5 0 R 54 | >> 55 | endobj 56 | 57 | 5 0 obj 58 | << /Kids [ 4 0 R ] 59 | /Count 1 60 | /Type /Pages 61 | >> 62 | endobj 63 | 64 | 6 0 obj 65 | << /Type /Catalog 66 | /Pages 5 0 R 67 | >> 68 | endobj 69 | 70 | xref 71 | 0 7 72 | 0000000000 65535 f 73 | 0000000010 00000 n 74 | 0000000034 00000 n 75 | 0000001090 00000 n 76 | 0000001113 00000 n 77 | 0000001286 00000 n 78 | 0000001360 00000 n 79 | trailer 80 | << /ID [ (some) (id) ] 81 | /Root 6 0 R 82 | /Size 7 83 | >> 84 | startxref 85 | 1419 86 | %%EOF -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_heart_filled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ico_heart_filled.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "original" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_heart_filled.imageset/ico_heart_filled.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << /BBox [ 0.000000 0.000000 24.458130 24.458130 ] 5 | /Resources << >> 6 | /Subtype /Form 7 | /Length 2 0 R 8 | /Group << /Type /Group 9 | /S /Transparency 10 | >> 11 | /Type /XObject 12 | >> 13 | stream 14 | /DeviceRGB CS 15 | /DeviceRGB cs 16 | q 17 | 1.000000 0.000000 -0.000000 1.000000 0.000000 1.834370 cm 18 | 1.000000 0.470238 0.000000 scn 19 | 16.364235 20.789410 m 20 | 14.400527 20.789410 12.515819 19.871731 11.285679 18.421570 c 21 | 10.055540 19.871731 8.170832 20.789410 6.207124 20.789410 c 22 | 2.731134 20.789410 0.000000 18.047701 0.000000 14.558252 c 23 | 0.000000 10.275747 3.837131 6.786298 9.649256 1.484148 c 24 | 11.285679 0.000000 l 25 | 12.922103 1.495478 l 26 | 18.734228 6.786298 22.571358 10.275747 22.571358 14.558252 c 27 | 22.571358 18.047701 19.840223 20.789410 16.364235 20.789410 c 28 | h 29 | 11.398537 3.172228 m 30 | 11.285679 3.058933 l 31 | 11.172822 3.172228 l 32 | 5.800838 8.055190 2.257136 11.284061 2.257136 14.558252 c 33 | 2.257136 16.824127 3.949988 18.523535 6.207124 18.523535 c 34 | 7.945118 18.523535 9.637970 17.401926 10.236111 15.849800 c 35 | 12.346533 15.849800 l 36 | 12.933388 17.401926 14.626241 18.523535 16.364235 18.523535 c 37 | 18.621370 18.523535 20.314222 16.824127 20.314222 14.558252 c 38 | 20.314222 11.284061 16.770519 8.055190 11.398537 3.172228 c 39 | h 40 | f 41 | n 42 | Q 43 | q 44 | 1.000000 0.000000 -0.000000 1.000000 0.857224 1.129318 cm 45 | 1.000000 0.470238 0.000000 scn 46 | 0.722644 17.828812 m 47 | 3.922644 22.628811 8.389311 19.828812 10.222644 17.828812 c 48 | 11.889310 19.995478 16.122641 23.028812 19.722641 17.828812 c 49 | 23.322641 12.628811 14.889309 5.328812 10.222644 2.328812 c 50 | 5.722644 5.495478 -2.477356 13.028811 0.722644 17.828812 c 51 | h 52 | f 53 | n 54 | Q 55 | 56 | endstream 57 | endobj 58 | 59 | 2 0 obj 60 | 1361 61 | endobj 62 | 63 | 3 0 obj 64 | << /BBox [ 0.000000 0.000000 24.458130 24.458130 ] 65 | /Resources << >> 66 | /Subtype /Form 67 | /Length 4 0 R 68 | /Group << /Type /Group 69 | /S /Transparency 70 | >> 71 | /Type /XObject 72 | >> 73 | stream 74 | /DeviceRGB CS 75 | /DeviceRGB cs 76 | q 77 | 1.000000 0.000000 -0.000000 1.000000 -1.222870 0.000000 cm 78 | 0.000000 0.000000 0.000000 scn 79 | 0.000000 24.458130 m 80 | 24.458128 24.458130 l 81 | 24.458128 0.000002 l 82 | 0.000000 0.000002 l 83 | 0.000000 24.458130 l 84 | h 85 | f 86 | n 87 | Q 88 | 89 | endstream 90 | endobj 91 | 92 | 4 0 obj 93 | 233 94 | endobj 95 | 96 | 5 0 obj 97 | << /BBox [ 0.000000 0.000000 24.458130 24.458130 ] 98 | /Resources << /XObject << /X1 1 0 R >> 99 | /ExtGState << /E1 << /SMask << /Type /Mask 100 | /G 3 0 R 101 | /S /Alpha 102 | >> 103 | /Type /ExtGState 104 | >> >> 105 | >> 106 | /Subtype /Form 107 | /Length 6 0 R 108 | /Group << /Type /Group 109 | /S /Transparency 110 | >> 111 | /Type /XObject 112 | >> 113 | stream 114 | /DeviceRGB CS 115 | /DeviceRGB cs 116 | q 117 | /E1 gs 118 | /X1 Do 119 | Q 120 | 121 | endstream 122 | endobj 123 | 124 | 6 0 obj 125 | 46 126 | endobj 127 | 128 | 7 0 obj 129 | << /BBox [ 0.000000 0.000000 24.458130 24.458130 ] 130 | /Resources << >> 131 | /Subtype /Form 132 | /Length 8 0 R 133 | /Group << /Type /Group 134 | /S /Transparency 135 | >> 136 | /Type /XObject 137 | >> 138 | stream 139 | /DeviceRGB CS 140 | /DeviceRGB cs 141 | q 142 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm 143 | 0.000000 0.000000 0.000000 scn 144 | 0.000000 24.458130 m 145 | 24.458128 24.458130 l 146 | 24.458128 0.000002 l 147 | 0.000000 0.000002 l 148 | 0.000000 24.458130 l 149 | h 150 | f 151 | n 152 | Q 153 | 154 | endstream 155 | endobj 156 | 157 | 8 0 obj 158 | 232 159 | endobj 160 | 161 | 9 0 obj 162 | << /XObject << /X1 5 0 R >> 163 | /ExtGState << /E1 << /SMask << /Type /Mask 164 | /G 7 0 R 165 | /S /Alpha 166 | >> 167 | /Type /ExtGState 168 | >> >> 169 | >> 170 | endobj 171 | 172 | 10 0 obj 173 | << /Length 11 0 R >> 174 | stream 175 | /DeviceRGB CS 176 | /DeviceRGB cs 177 | q 178 | /E1 gs 179 | /X1 Do 180 | Q 181 | 182 | endstream 183 | endobj 184 | 185 | 11 0 obj 186 | 46 187 | endobj 188 | 189 | 12 0 obj 190 | << /Annots [] 191 | /Type /Page 192 | /MediaBox [ 0.000000 0.000000 24.458130 24.458130 ] 193 | /Resources 9 0 R 194 | /Contents 10 0 R 195 | /Parent 13 0 R 196 | >> 197 | endobj 198 | 199 | 13 0 obj 200 | << /Kids [ 12 0 R ] 201 | /Count 1 202 | /Type /Pages 203 | >> 204 | endobj 205 | 206 | 14 0 obj 207 | << /Type /Catalog 208 | /Pages 13 0 R 209 | >> 210 | endobj 211 | 212 | xref 213 | 0 15 214 | 0000000000 65535 f 215 | 0000000010 00000 n 216 | 0000001619 00000 n 217 | 0000001642 00000 n 218 | 0000002123 00000 n 219 | 0000002145 00000 n 220 | 0000002811 00000 n 221 | 0000002832 00000 n 222 | 0000003312 00000 n 223 | 0000003334 00000 n 224 | 0000003632 00000 n 225 | 0000003736 00000 n 226 | 0000003758 00000 n 227 | 0000003934 00000 n 228 | 0000004010 00000 n 229 | trailer 230 | << /ID [ (some) (id) ] 231 | /Root 14 0 R 232 | /Size 15 233 | >> 234 | startxref 235 | 4071 236 | %%EOF -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_left_arrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ico_left_arrow.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_left_arrow.imageset/ico_left_arrow.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << /BBox [ 0.000000 0.000000 24.458130 24.458130 ] 5 | /Resources << >> 6 | /Subtype /Form 7 | /Length 2 0 R 8 | /Group << /Type /Group 9 | /S /Transparency 10 | >> 11 | /Type /XObject 12 | >> 13 | stream 14 | /DeviceRGB CS 15 | /DeviceRGB cs 16 | q 17 | 1.000000 0.000000 -0.000000 1.000000 0.000000 11.241058 cm 18 | 1.000000 1.000000 1.000000 scn 19 | 23.470154 1.975952 m 20 | 0.987975 1.975952 l 21 | 0.442348 1.975952 0.000000 1.533604 0.000000 0.987978 c 22 | 0.000000 0.442305 0.442348 0.000005 0.987975 0.000005 c 23 | 23.470154 0.000005 l 24 | 24.015827 0.000005 24.458128 0.442305 24.458128 0.987978 c 25 | 24.458128 1.533604 24.015827 1.975952 23.470154 1.975952 c 26 | h 27 | f 28 | n 29 | Q 30 | q 31 | 1.000000 0.000000 -0.000000 1.000000 0.000000 2.713867 cm 32 | 1.000000 1.000000 1.000000 scn 33 | 2.385228 9.515194 m 34 | 10.117388 17.247400 l 35 | 10.503224 17.633236 10.503224 18.258781 10.117388 18.644619 c 36 | 9.731551 19.030407 9.106007 19.030407 8.720170 18.644619 c 37 | 0.289377 10.213827 l 38 | -0.096459 9.827991 -0.096459 9.202445 0.289377 8.816609 c 39 | 8.720170 0.385817 l 40 | 8.913064 0.192873 9.165957 0.096426 9.418802 0.096426 c 41 | 9.671648 0.096426 9.924541 0.192873 10.117435 0.385817 c 42 | 10.503272 0.771652 10.503272 1.397198 10.117435 1.783033 c 43 | 2.385228 9.515194 l 44 | h 45 | f 46 | n 47 | Q 48 | 49 | endstream 50 | endobj 51 | 52 | 2 0 obj 53 | 973 54 | endobj 55 | 56 | 3 0 obj 57 | << /BBox [ 0.000000 0.000000 24.458130 24.458130 ] 58 | /Resources << >> 59 | /Subtype /Form 60 | /Length 4 0 R 61 | /Group << /Type /Group 62 | /S /Transparency 63 | >> 64 | /Type /XObject 65 | >> 66 | stream 67 | /DeviceRGB CS 68 | /DeviceRGB cs 69 | q 70 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm 71 | 0.000000 0.000000 0.000000 scn 72 | 0.000000 24.458130 m 73 | 24.458128 24.458130 l 74 | 24.458128 0.000002 l 75 | 0.000000 0.000002 l 76 | 0.000000 24.458130 l 77 | h 78 | f 79 | n 80 | Q 81 | 82 | endstream 83 | endobj 84 | 85 | 4 0 obj 86 | 232 87 | endobj 88 | 89 | 5 0 obj 90 | << /XObject << /X1 1 0 R >> 91 | /ExtGState << /E1 << /SMask << /Type /Mask 92 | /G 3 0 R 93 | /S /Alpha 94 | >> 95 | /Type /ExtGState 96 | >> >> 97 | >> 98 | endobj 99 | 100 | 6 0 obj 101 | << /Length 7 0 R >> 102 | stream 103 | /DeviceRGB CS 104 | /DeviceRGB cs 105 | q 106 | /E1 gs 107 | /X1 Do 108 | Q 109 | 110 | endstream 111 | endobj 112 | 113 | 7 0 obj 114 | 46 115 | endobj 116 | 117 | 8 0 obj 118 | << /Annots [] 119 | /Type /Page 120 | /MediaBox [ 0.000000 0.000000 24.458130 24.458130 ] 121 | /Resources 5 0 R 122 | /Contents 6 0 R 123 | /Parent 9 0 R 124 | >> 125 | endobj 126 | 127 | 9 0 obj 128 | << /Kids [ 8 0 R ] 129 | /Count 1 130 | /Type /Pages 131 | >> 132 | endobj 133 | 134 | 10 0 obj 135 | << /Type /Catalog 136 | /Pages 9 0 R 137 | >> 138 | endobj 139 | 140 | xref 141 | 0 11 142 | 0000000000 65535 f 143 | 0000000010 00000 n 144 | 0000001231 00000 n 145 | 0000001253 00000 n 146 | 0000001733 00000 n 147 | 0000001755 00000 n 148 | 0000002053 00000 n 149 | 0000002155 00000 n 150 | 0000002176 00000 n 151 | 0000002349 00000 n 152 | 0000002423 00000 n 153 | trailer 154 | << /ID [ (some) (id) ] 155 | /Root 10 0 R 156 | /Size 11 157 | >> 158 | startxref 159 | 2483 160 | %%EOF -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_plane.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ico_plane.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_plane.imageset/ico_plane.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << >> 5 | endobj 6 | 7 | 2 0 obj 8 | << /Length 3 0 R >> 9 | stream 10 | /DeviceRGB CS 11 | /DeviceRGB cs 12 | q 13 | 1.000000 0.000000 -0.000000 1.000000 -0.000198 0.397034 cm 14 | 0.839714 0.839714 0.839714 scn 15 | 15.881774 7.543835 m 16 | 15.881774 8.179106 15.325912 8.734968 14.690641 8.734968 c 17 | 10.323153 8.734968 l 18 | 6.352710 15.087677 l 19 | 4.764532 15.087677 l 20 | 6.749754 8.734968 l 21 | 2.382266 8.734968 l 22 | 1.191133 10.323145 l 23 | 0.000000 10.323145 l 24 | 0.794089 7.543835 l 25 | 0.000000 4.764524 l 26 | 1.191133 4.764524 l 27 | 2.382266 6.352702 l 28 | 6.749754 6.352702 l 29 | 4.764532 -0.000008 l 30 | 6.352710 -0.000008 l 31 | 10.323153 6.352702 l 32 | 14.690641 6.352702 l 33 | 15.325912 6.352702 15.881774 6.908564 15.881774 7.543835 c 34 | h 35 | f 36 | n 37 | Q 38 | 39 | endstream 40 | endobj 41 | 42 | 3 0 obj 43 | 596 44 | endobj 45 | 46 | 4 0 obj 47 | << /Annots [] 48 | /Type /Page 49 | /MediaBox [ 0.000000 0.000000 15.881775 15.881775 ] 50 | /Resources 1 0 R 51 | /Contents 2 0 R 52 | /Parent 5 0 R 53 | >> 54 | endobj 55 | 56 | 5 0 obj 57 | << /Kids [ 4 0 R ] 58 | /Count 1 59 | /Type /Pages 60 | >> 61 | endobj 62 | 63 | 6 0 obj 64 | << /Type /Catalog 65 | /Pages 5 0 R 66 | >> 67 | endobj 68 | 69 | xref 70 | 0 7 71 | 0000000000 65535 f 72 | 0000000010 00000 n 73 | 0000000034 00000 n 74 | 0000000686 00000 n 75 | 0000000708 00000 n 76 | 0000000881 00000 n 77 | 0000000955 00000 n 78 | trailer 79 | << /ID [ (some) (id) ] 80 | /Root 6 0 R 81 | /Size 7 82 | >> 83 | startxref 84 | 1014 85 | %%EOF -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_share.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ico_share.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_share.imageset/ico_share.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << >> 5 | endobj 6 | 7 | 2 0 obj 8 | << /Length 3 0 R >> 9 | stream 10 | /DeviceRGB CS 11 | /DeviceRGB cs 12 | q 13 | 1.000000 0.000000 -0.000000 1.000000 3.054688 2.117569 cm 14 | 1.000000 0.470238 0.000000 scn 15 | 15.270935 5.945481 m 16 | 14.497208 5.945481 13.804927 5.640061 13.275534 5.161572 c 17 | 6.016748 9.386532 l 18 | 6.067651 9.620687 6.108374 9.854840 6.108374 10.099175 c 19 | 6.108374 10.343511 6.067651 10.577665 6.016748 10.811819 c 20 | 13.194088 14.996056 l 21 | 13.743842 14.487024 14.466666 14.171426 15.270935 14.171426 c 22 | 16.960918 14.171426 18.325123 15.535629 18.325123 17.225613 c 23 | 18.325123 18.915596 16.960918 20.279800 15.270935 20.279800 c 24 | 13.580952 20.279800 12.216748 18.915596 12.216748 17.225613 c 25 | 12.216748 16.981277 12.257471 16.747124 12.308374 16.512970 c 26 | 5.131034 12.328732 l 27 | 4.581281 12.837763 3.858456 13.153363 3.054187 13.153363 c 28 | 1.364204 13.153363 0.000000 11.789160 0.000000 10.099175 c 29 | 0.000000 8.409192 1.364204 7.044989 3.054187 7.044989 c 30 | 3.858456 7.044989 4.581281 7.360588 5.131034 7.869619 c 31 | 12.379638 3.634480 l 32 | 12.328735 3.420685 12.298193 3.196712 12.298193 2.972738 c 33 | 12.298193 1.333658 13.631855 -0.000004 15.270935 -0.000004 c 34 | 16.910015 -0.000004 18.243677 1.333658 18.243677 2.972738 c 35 | 18.243677 4.611819 16.910015 5.945481 15.270935 5.945481 c 36 | h 37 | f 38 | n 39 | Q 40 | 41 | endstream 42 | endobj 43 | 44 | 3 0 obj 45 | 1186 46 | endobj 47 | 48 | 4 0 obj 49 | << /Annots [] 50 | /Type /Page 51 | /MediaBox [ 0.000000 0.000000 24.433502 24.433502 ] 52 | /Resources 1 0 R 53 | /Contents 2 0 R 54 | /Parent 5 0 R 55 | >> 56 | endobj 57 | 58 | 5 0 obj 59 | << /Kids [ 4 0 R ] 60 | /Count 1 61 | /Type /Pages 62 | >> 63 | endobj 64 | 65 | 6 0 obj 66 | << /Type /Catalog 67 | /Pages 5 0 R 68 | >> 69 | endobj 70 | 71 | xref 72 | 0 7 73 | 0000000000 65535 f 74 | 0000000010 00000 n 75 | 0000000034 00000 n 76 | 0000001276 00000 n 77 | 0000001299 00000 n 78 | 0000001472 00000 n 79 | 0000001546 00000 n 80 | trailer 81 | << /ID [ (some) (id) ] 82 | /Root 6 0 R 83 | /Size 7 84 | >> 85 | startxref 86 | 1605 87 | %%EOF -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_star.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ico_star.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Resources/Assets/Icons.xcassets/ico_star.imageset/ico_star.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.7 2 | 3 | 1 0 obj 4 | << >> 5 | endobj 6 | 7 | 2 0 obj 8 | << /Length 3 0 R >> 9 | stream 10 | /DeviceRGB CS 11 | /DeviceRGB cs 12 | q 13 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.351841 cm 14 | 1.000000 0.470238 0.000000 scn 15 | 7.031712 2.620705 m 16 | 11.377310 0.000000 l 17 | 10.227612 4.942576 l 18 | 14.063424 8.266479 l 19 | 9.006934 8.700350 l 20 | 7.031712 13.360250 l 21 | 5.056518 8.700350 l 22 | 0.000000 8.266479 l 23 | 3.835813 4.942576 l 24 | 2.686114 0.000000 l 25 | 7.031712 2.620705 l 26 | h 27 | f 28 | n 29 | Q 30 | 31 | endstream 32 | endobj 33 | 34 | 3 0 obj 35 | 351 36 | endobj 37 | 38 | 4 0 obj 39 | << /Annots [] 40 | /Type /Page 41 | /MediaBox [ 0.000000 0.000000 14.063416 14.063423 ] 42 | /Resources 1 0 R 43 | /Contents 2 0 R 44 | /Parent 5 0 R 45 | >> 46 | endobj 47 | 48 | 5 0 obj 49 | << /Kids [ 4 0 R ] 50 | /Count 1 51 | /Type /Pages 52 | >> 53 | endobj 54 | 55 | 6 0 obj 56 | << /Type /Catalog 57 | /Pages 5 0 R 58 | >> 59 | endobj 60 | 61 | xref 62 | 0 7 63 | 0000000000 65535 f 64 | 0000000010 00000 n 65 | 0000000034 00000 n 66 | 0000000441 00000 n 67 | 0000000463 00000 n 68 | 0000000636 00000 n 69 | 0000000710 00000 n 70 | trailer 71 | << /ID [ (some) (id) ] 72 | /Root 6 0 R 73 | /Size 7 74 | >> 75 | startxref 76 | 769 77 | %%EOF -------------------------------------------------------------------------------- /Resources/Localization/Localizable.strings: -------------------------------------------------------------------------------- 1 | /** 2 | * Apple Strings File 3 | * Generated by Twine 1.0.4 4 | * Language: en 5 | */ 6 | -------------------------------------------------------------------------------- /Resources/StoryBoards/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Resources/StoryBoards/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------