├── Gemfile ├── SortingAlgorithms ├── SupportingFiles │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── SortingAlgorithmsLogo.001.jpeg │ │ │ └── Contents.json │ │ ├── ic_bubble.imageset │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ └── Contents.json │ │ ├── ic_insertion.imageset │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ └── Contents.json │ │ ├── ic_quick_sorting.imageset │ │ │ ├── quick_sorting.png │ │ │ ├── quick_sorting@2x.png │ │ │ ├── quick_sorting@3x.png │ │ │ └── Contents.json │ │ └── ic_selection.imageset │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Info.plist │ └── Base.lproj │ │ └── LaunchScreen.storyboard ├── Scenes │ ├── AlgorithmsList │ │ ├── AlgorithmsListProtocols.swift │ │ ├── AlgorithmsListRouter.swift │ │ ├── AlgorithmsListPresenter.swift │ │ ├── AlgorithmsListCell.swift │ │ └── AlgorithmsListViewController.swift │ ├── DataSourceInput │ │ ├── DataSourceProtocols.swift │ │ ├── DataSourceRouter.swift │ │ ├── DataSourcePresenter.swift │ │ └── DataSourceViewController.swift │ └── AlgorithmDetail │ │ ├── AlgorithmDetailProtocol.swift │ │ ├── AlgorithmDetailRouter.swift │ │ ├── AlgorithmDetailCell.swift │ │ ├── AlgorithmDetailPresenter.swift │ │ └── AlgorithmDetailViewController.swift ├── Algorithms │ ├── Algorithm.swift │ ├── InsertionSort.swift │ ├── BubbleSort.swift │ ├── SelectionSort.swift │ └── QuickSort.swift ├── Extensions │ └── UICollectionViewCell.swift └── CustomComponents │ └── PaddedTextField.swift ├── SortingAlgorithms.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── VictorMagalhaes.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── VictorMagalhaes.xcuserdatad │ │ ├── xcschemes │ │ └── xcschememanagement.plist │ │ └── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist ├── xcshareddata │ └── xcschemes │ │ ├── SortingAlgorithmsTests.xcscheme │ │ └── SortingAlgorithms.xcscheme └── project.pbxproj ├── fastlane ├── Appfile ├── report.xml ├── README.md ├── Fastfile └── test_output │ ├── report.junit │ └── report.html ├── SortingAlgorithmsTests ├── Info.plist ├── AlgorithmsTests │ ├── BubbleSortTests.swift │ ├── QuickSortTests.swift │ ├── InsertionSortTests.swift │ └── SelectionSortTests.swift └── ModulesTests │ ├── AlgorithmsList │ └── AlgorithmsListPresenterTests.swift │ └── AlgorithmDetail │ └── AlgorithmDetailPresenterTests.swift ├── .github └── workflows │ └── swift.yml ├── README.md └── Gemfile.lock /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_bubble.imageset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_bubble.imageset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_bubble.imageset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_bubble.imageset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_insertion.imageset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_insertion.imageset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_insertion.imageset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_insertion.imageset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_quick_sorting.imageset/quick_sorting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_quick_sorting.imageset/quick_sorting.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_selection.imageset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_selection.imageset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_selection.imageset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_selection.imageset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_quick_sorting.imageset/quick_sorting@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_quick_sorting.imageset/quick_sorting@2x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_quick_sorting.imageset/quick_sorting@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_quick_sorting.imageset/quick_sorting@3x.png -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/SortingAlgorithmsLogo.001.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/SortingAlgorithmsLogo.001.jpeg -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/project.xcworkspace/xcuserdata/VictorMagalhaes.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorpanitz/iOS-SortingAlgorithmsApp/HEAD/SortingAlgorithms.xcodeproj/project.xcworkspace/xcuserdata/VictorMagalhaes.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | app_identifier("victorPanitz.Developer.SortingAlgorithms") # The bundle identifier of your app 2 | apple_id("victorpanitz@gmail.com") # Your Apple email address 3 | 4 | itc_team_id("118534860") # App Store Connect Team ID 5 | team_id("PFBFJV3F25") # Developer Portal Team ID 6 | 7 | # For more information about the Appfile, see: 8 | # https://docs.fastlane.tools/advanced/#appfile 9 | -------------------------------------------------------------------------------- /fastlane/report.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_bubble.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Icon-App-60x60@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "Icon-App-60x60@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_insertion.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Icon-App-60x60@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "Icon-App-60x60@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_selection.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Icon-App-60x60@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "Icon-App-60x60@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmsList/AlgorithmsListProtocols.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor Magalhaes on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AlgorithmsListView: AnyObject { 12 | func setNavigationBarTitle(_ text: String) 13 | func updateDataSource(dataSource: [Algorithm]) 14 | } 15 | 16 | protocol AlgorithmsListRoutering: AnyObject { 17 | func navigateToAlgorithmDetail(algorithm: Algorithm) 18 | } 19 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/DataSourceInput/DataSourceProtocols.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataSourceProtocols.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 05/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol DataSourceView: AnyObject { 12 | func clearInputField() 13 | func updateArray(_ text: String) 14 | func setNavigationBarTitle(_ text: String) 15 | } 16 | 17 | protocol DataSourceRoutering: AnyObject { 18 | func navigateToAlgorithmDetail(dataSource: [Int]) 19 | } 20 | -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/ic_quick_sorting.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "quick_sorting.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "quick_sorting@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "quick_sorting@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmDetail/AlgorithmDetailProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmDetailProtocol.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AlgorithmDetailView: AnyObject { 12 | func updateDataSource(_ datasource: [Int]) 13 | func updateDataSourceAndReloadData(_ datasource: [Int]) 14 | func swapCell(x0: Int, x1: Int) 15 | func setNavigationBarTitle(_ text: String) 16 | func toggleRestartButton(_ isEnable: Bool) 17 | } 18 | 19 | protocol AlgorithmDetailRoutering: AnyObject { 20 | func dismiss() 21 | } 22 | -------------------------------------------------------------------------------- /SortingAlgorithms/Algorithms/Algorithm.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmInterface.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol Algorithm: AnyObject { 12 | var title: String { get set } 13 | var description: String { get set } 14 | var image: String { get set } 15 | 16 | func generateSwaps(from list: [Int]) -> [(x0: Int, x1: Int)] 17 | func swapDataSource( datasource: inout [Int], x0: Int, x1: Int) 18 | } 19 | 20 | extension Algorithm { 21 | func swapDataSource(datasource: inout [Int], x0: Int, x1: Int) { 22 | datasource.swapAt(x0, x1) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SortingAlgorithmsTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 02/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | 19 | window = UIWindow(frame: UIScreen.main.bounds) 20 | let router = AlgorithmsListRouter() 21 | window?.rootViewController = UINavigationController(rootViewController: router.makeViewController()) 22 | window?.makeKeyAndVisible() 23 | 24 | return true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | Install _fastlane_ using 12 | ``` 13 | [sudo] gem install fastlane -NV 14 | ``` 15 | or alternatively using `brew cask install fastlane` 16 | 17 | # Available Actions 18 | ## iOS 19 | ### ios beta 20 | ``` 21 | fastlane ios beta 22 | ``` 23 | Push a new beta build to TestFlight 24 | ### ios tests 25 | ``` 26 | fastlane ios tests 27 | ``` 28 | Run current tests 29 | 30 | ---- 31 | 32 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 33 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 34 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 35 | -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/xcuserdata/VictorMagalhaes.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SortingAlgorithms.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | SortingAlgorithmsTests.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 716548802253DE8C009C41DD 21 | 22 | primary 23 | 24 | 25 | 716548942253DE8D009C41DD 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmsList/AlgorithmsListRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmsListRouter.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor Magalhaes on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class AlgorithmsListRouter: AlgorithmsListRoutering { 13 | 14 | private weak var view: UIViewController? 15 | 16 | init() {} 17 | 18 | func makeViewController() -> UIViewController { 19 | let presenter = AlgorithmsListPresenter(router: self) 20 | let viewController = AlgorithmsListViewController(presenter: presenter) 21 | self.view = viewController 22 | 23 | return viewController 24 | } 25 | 26 | func navigateToAlgorithmDetail(algorithm: Algorithm) { 27 | let router = DataSourceRouter(algorithm: algorithm) 28 | view?.navigationController?.pushViewController(router.makeViewController(), animated: true) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/DataSourceInput/DataSourceRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataSourceRouter.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 05/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class DataSourceRouter: DataSourceRoutering { 13 | 14 | private weak var view: UIViewController? 15 | private let algorithm: Algorithm 16 | 17 | init(algorithm: Algorithm) { 18 | self.algorithm = algorithm 19 | } 20 | 21 | func makeViewController() -> UIViewController { 22 | let presenter = DataSourcePresenter(router: self) 23 | let viewController = DataSourceViewController(presenter: presenter) 24 | self.view = viewController 25 | 26 | return viewController 27 | } 28 | 29 | func navigateToAlgorithmDetail(dataSource: [Int]) { 30 | let router = AlgorithmDetailRouter(algorithm: algorithm, datasource: dataSource) 31 | 32 | view?.navigationController?.pushViewController(router.makeViewController(), animated: true) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # This file contains the fastlane.tools configuration 2 | # You can find the documentation at https://docs.fastlane.tools 3 | # 4 | # For a list of all available actions, check out 5 | # 6 | # https://docs.fastlane.tools/actions 7 | # 8 | # For a list of all available plugins, check out 9 | # 10 | # https://docs.fastlane.tools/plugins/available-plugins 11 | # 12 | 13 | # Uncomment the line if you want fastlane to automatically update itself 14 | # update_fastlane 15 | 16 | default_platform(:ios) 17 | 18 | platform :ios do 19 | 20 | desc "Push a new beta build to TestFlight" 21 | lane :beta do 22 | tests 23 | increment_build_number(build_number: number_of_commits) 24 | get_certificates( 25 | development: true, 26 | username: "victorpanitz@gmail.com" 27 | ) 28 | sigh(force: true) 29 | enable_automatic_code_signing 30 | gym(scheme: "SortingAlgorithms", export_method: "development") 31 | upload_to_testflight 32 | end 33 | 34 | desc "Run current tests" 35 | lane :tests do 36 | run_tests(scheme: "SortingAlgorithmsTests") 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /SortingAlgorithms/Extensions/UICollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UICollectionViewCell.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor Magalhaes on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UICollectionView { 12 | func dequeue(_ reusableCell: String, for indexPath: IndexPath) -> UICollectionViewCell { 13 | return self.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) 14 | } 15 | 16 | func swap(_ x0: Int, _ x1: Int, completion: @escaping (_ result: Bool) -> Void) { 17 | self.performBatchUpdates({ () -> Void in 18 | 19 | self.moveItem( 20 | at: IndexPath(item: x0, section: 0), 21 | to: IndexPath(item: x1, section: 0) 22 | ) 23 | 24 | self.moveItem( 25 | at: IndexPath(item: x1, section: 0), 26 | to: IndexPath(item: x0, section: 0) 27 | ) 28 | 29 | }, completion: { success in 30 | completion(success) 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/swift.yml: -------------------------------------------------------------------------------- 1 | name: Swift 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: macos-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Build 17 | run: swift build -v 18 | - name: Run tests 19 | run: swift test -v 20 | - name: Codecov 21 | uses: codecov/codecov-action@v1.0.7 22 | with: 23 | # User defined upload name. Visible in Codecov UI 24 | name: # optional 25 | # Repository upload token - get it from codecov.io. Required only for private repositories 26 | token: # optional 27 | # Path to coverage file to upload 28 | file: # optional 29 | # Flag upload to group coverage metrics (e.g. unittests | integration | ui,chrome) 30 | flags: # optional 31 | # Environment variables to tag the upload with (e.g. PYTHON | OS,PYTHON) 32 | env_vars: # optional 33 | # Specify whether or not CI build should fail if Codecov runs into an error during upload 34 | fail_ci_if_error: # optional 35 | -------------------------------------------------------------------------------- /SortingAlgorithms/Algorithms/InsertionSort.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InsertionSort.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class InsertionSort: Algorithm { 12 | 13 | final var title: String = "Insertion Sort" 14 | final var image: String = "ic_insertion" 15 | final var description: String = "Insertion Sort Description" 16 | 17 | final func generateSwaps(from list: [Int]) -> [(x0: Int, x1: Int)] { 18 | if list.count == 1 { return [] } 19 | 20 | var array = list 21 | var swaps = [(x0: Int, x1: Int)]() 22 | 23 | for i in 1...max(1, array.count - 1) { 24 | var pos = i 25 | 26 | for j in (0...i-1).reversed() { 27 | if array[pos] < array[j] { 28 | swaps.append((x0: j, x1: pos)) 29 | array.swapAt(j, pos) 30 | pos = j 31 | } 32 | } 33 | } 34 | 35 | return swaps 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmDetail/AlgorithmDetailRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmDetailRouter.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor Magalhaes on 06/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class AlgorithmDetailRouter: AlgorithmDetailRoutering { 13 | 14 | private weak var view: UIViewController? 15 | private let algorithm: Algorithm 16 | private let dataSource: [Int] 17 | 18 | init(algorithm: Algorithm, datasource: [Int]) { 19 | self.algorithm = algorithm 20 | self.dataSource = datasource 21 | } 22 | 23 | func makeViewController() -> UIViewController { 24 | let presenter = AlgorithmDetailPresenter(router: self, algorithm: algorithm, datasource: dataSource) 25 | let viewController = AlgorithmDetailViewController(presenter: presenter) 26 | self.view = viewController 27 | 28 | return viewController 29 | } 30 | 31 | func dismiss() { 32 | view?.navigationController?.popToRootViewController(animated: true) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SortingAlgorithms/Algorithms/BubbleSort.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleSort.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class BubbleSort: Algorithm { 12 | 13 | final var title: String = "Bubble Sort" 14 | final var image: String = "ic_bubble" 15 | final var description: String = "Bubble Sort Description" 16 | 17 | final func generateSwaps(from list: [Int]) -> [(x0: Int, x1: Int)] { 18 | if list.count == 1 { return [] } 19 | 20 | var array = list 21 | var isSorting = true 22 | var swaps = [(x0: Int, x1: Int)]() 23 | 24 | while isSorting { 25 | isSorting = false 26 | 27 | for i in 0.. array[i+1] { 29 | isSorting = true 30 | swaps.append((x0: i, x1: i+1)) 31 | array.swapAt(i, i+1) 32 | } 33 | } 34 | } 35 | 36 | return swaps 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /SortingAlgorithms/CustomComponents/PaddedTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PaddedTextField.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 05/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class PaddedTextField: UITextField { 13 | 14 | @available(*, unavailable) 15 | required init?(coder aDecoder: NSCoder) { return nil } 16 | 17 | override init(frame: CGRect) { 18 | super.init(frame: frame) 19 | } 20 | 21 | override func textRect(forBounds bounds: CGRect) -> CGRect { 22 | return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width - 20, height: bounds.height) 23 | } 24 | 25 | override func editingRect(forBounds bounds: CGRect) -> CGRect { 26 | return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width - 20, height: bounds.height) 27 | } 28 | 29 | override func placeholderRect(forBounds bounds: CGRect) -> CGRect { 30 | return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width - 20, height: bounds.height) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmsList/AlgorithmsListPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmsListPresenter.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor Magalhaes on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class AlgorithmsListPresenter { 12 | 13 | private weak var view: AlgorithmsListView? 14 | private let router: AlgorithmsListRoutering 15 | 16 | private let dataSource: [Algorithm] = [ 17 | BubbleSort(), 18 | InsertionSort(), 19 | SelectionSort(), 20 | QuickSort() 21 | ] 22 | 23 | init (router: AlgorithmsListRoutering) { 24 | self.router = router 25 | } 26 | 27 | func attachView(_ view: AlgorithmsListView) { 28 | self.view = view 29 | 30 | view.updateDataSource(dataSource: dataSource) 31 | } 32 | 33 | func viewWillAppear() { 34 | view?.setNavigationBarTitle("Sorting Algorithms") 35 | } 36 | 37 | func itemTriggered(index: Int) { 38 | if (0.. [(x0: Int, x1: Int)] { 18 | if list.count == 1 { return [] } 19 | 20 | var array = list 21 | var swaps = [(x0: Int, x1: Int)]() 22 | 23 | array.enumerated().forEach { (arg) in 24 | 25 | let (i, _) = arg 26 | 27 | var minValue = array[i] 28 | var minPos = i 29 | 30 | (i.. 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.2 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationPortraitUpsideDown 33 | 34 | UISupportedInterfaceOrientations~ipad 35 | 36 | UIInterfaceOrientationPortrait 37 | UIInterfaceOrientationPortraitUpsideDown 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmDetail/AlgorithmDetailCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmDetailCell.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | final class AlgorithmDetailCell: UICollectionViewCell { 13 | 14 | var label: UILabel = { 15 | let label = UILabel() 16 | label.textAlignment = .center 17 | label.backgroundColor = .clear 18 | label.minimumScaleFactor = 0.5 19 | label.contentScaleFactor = 0.5 20 | label.adjustsFontSizeToFitWidth = true 21 | label.translatesAutoresizingMaskIntoConstraints = false 22 | return label 23 | }() 24 | 25 | @available(*, unavailable) 26 | required init?(coder aDecoder: NSCoder) { return nil } 27 | 28 | override init(frame: CGRect) { 29 | super.init(frame: frame) 30 | 31 | setupCell() 32 | setupLabel() 33 | } 34 | 35 | private func setupCell() { 36 | layer.cornerRadius = 5 37 | backgroundColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1).withAlphaComponent(0.8) 38 | } 39 | 40 | private func setupLabel() { 41 | addSubview(label) 42 | 43 | NSLayoutConstraint.activate([ 44 | label.topAnchor.constraint(equalTo: topAnchor), 45 | label.bottomAnchor.constraint(equalTo: bottomAnchor), 46 | label.leadingAnchor.constraint(equalTo: leadingAnchor), 47 | label.trailingAnchor.constraint(equalTo: trailingAnchor), 48 | ]) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/DataSourceInput/DataSourcePresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataSourcePresenter.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 05/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class DataSourcePresenter { 12 | 13 | private weak var view: DataSourceView? 14 | private var array: [Int] = [Int]() 15 | private var newValue = String() 16 | private let router: DataSourceRoutering 17 | 18 | init(router: DataSourceRoutering) { 19 | self.router = router 20 | } 21 | 22 | func attachView(_ view: DataSourceView) { 23 | self.view = view 24 | } 25 | 26 | func viewDidAppear() { 27 | view?.setNavigationBarTitle("Array input") 28 | } 29 | 30 | func addButtonTriggered() { 31 | guard 32 | (0...40).contains(array.count + 1), 33 | newValue.count > 0, 34 | let value = Int(newValue) 35 | else { return } 36 | 37 | array.append(value) 38 | view?.clearInputField() 39 | newValue = "" 40 | view?.updateArray("\(array)") 41 | 42 | } 43 | 44 | func removeButtonTriggered() { 45 | if array.count > 0 { 46 | array.removeLast() 47 | view?.updateArray("\(array)") 48 | } 49 | } 50 | 51 | func inputDidChange(_ text: String) { 52 | newValue = text 53 | } 54 | 55 | func runTriggered() { 56 | if array.count > 0 { 57 | router.navigateToAlgorithmDetail(dataSource: array) 58 | } 59 | } 60 | 61 | func addSampleButtonTrigerred() { 62 | array = randomNumbers(10) 63 | view?.clearInputField() 64 | newValue = "" 65 | view?.updateArray("\(array)") 66 | } 67 | 68 | private func randomNumbers(_ total: Int) -> [Int] { 69 | return (0.. [(x0: Int, x1: Int)] { 20 | swaps.removeAll() 21 | guard list.count > 1 else { return [] } 22 | 23 | var copy = list; 24 | quicksort(array: ©, left: 0, right: list.count - 1); 25 | 26 | return swaps 27 | } 28 | } 29 | 30 | extension QuickSort { 31 | 32 | private func swap(array: inout [Int], num1: Int, num2: Int) { 33 | array.swapAt(num1, num2) 34 | swaps.append((x0: num1, x1: num2)) 35 | } 36 | 37 | private func quicksort ( array: inout [Int], left: Int, right: Int) { 38 | let pivot = right; 39 | var low = left; 40 | var high = right-1; 41 | 42 | if(right == low || high < low) { 43 | return 44 | } 45 | for _ in 0...array.count { 46 | if low <= high { 47 | if array[low] <= array[pivot] { 48 | low = low + 1 49 | continue 50 | } 51 | if array[high] > array[pivot] { 52 | high = high - 1 53 | continue 54 | } 55 | swap(array: &array, num1: low, num2: high); 56 | low = low + 1 57 | high = high - 1 58 | } else { 59 | if array[low] == array[pivot] { 60 | break 61 | } 62 | swap(array: &array, num1: pivot, num2: low) 63 | break 64 | } 65 | } 66 | quicksort(array: &array, left: left, right: high) 67 | quicksort(array: &array, left: low + 1, right: right) 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmDetail/AlgorithmDetailPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmDetailPresenter.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class AlgorithmDetailPresenter { 12 | 13 | private weak var view: AlgorithmDetailView? 14 | private let algorithm: Algorithm 15 | private lazy var dataSource = [Int]() 16 | private(set) var dataSourceBackup = [Int]() 17 | private var swaps = [(x0: Int, x1: Int)]() 18 | private let router: AlgorithmDetailRoutering 19 | 20 | init (router: AlgorithmDetailRoutering, algorithm: Algorithm, datasource: [Int]) { 21 | self.router = router 22 | self.algorithm = algorithm 23 | self.dataSource = datasource 24 | self.dataSourceBackup = datasource 25 | } 26 | 27 | func attachView(_ view: AlgorithmDetailView) { 28 | self.view = view 29 | 30 | view.setNavigationBarTitle(algorithm.title) 31 | view.updateDataSource(dataSource) 32 | generateSwaps() 33 | } 34 | 35 | private func generateSwaps() { 36 | swaps = algorithm.generateSwaps(from: dataSource) 37 | } 38 | 39 | func viewDidAppear() { 40 | startSwap() 41 | } 42 | 43 | func swapDidComplete() { 44 | startSwap() 45 | } 46 | 47 | func restartButtonTriggered() { 48 | dataSource = dataSourceBackup 49 | view?.toggleRestartButton(false) 50 | view?.updateDataSourceAndReloadData(dataSource) 51 | 52 | DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in 53 | guard let self = self else { return } 54 | self.generateSwaps() 55 | self.startSwap() 56 | } 57 | } 58 | 59 | private func startSwap() { 60 | guard swaps.count > 0 else { 61 | view?.toggleRestartButton(true) 62 | return 63 | } 64 | 65 | algorithm.swapDataSource(datasource: &dataSource, x0: swaps[0].x0, x1: swaps[0].x1) 66 | view?.updateDataSource(dataSource) 67 | view?.swapCell(x0: swaps[0].x0, x1: swaps[0].x1) 68 | swaps.removeFirst() 69 | } 70 | 71 | func closeButtonTriggered() { 72 | router.dismiss() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmsList/AlgorithmsListCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmListViewCell.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | final class AlgorithmsListCell: UICollectionViewCell { 13 | 14 | var imageView: UIImageView = { 15 | let imageView = UIImageView() 16 | imageView.contentMode = .scaleAspectFill 17 | imageView.translatesAutoresizingMaskIntoConstraints = false 18 | return imageView 19 | }() 20 | 21 | var label: UILabel = { 22 | let label = UILabel() 23 | label.textAlignment = .left 24 | label.textColor = .white 25 | label.translatesAutoresizingMaskIntoConstraints = false 26 | return label 27 | }() 28 | 29 | override var isSelected: Bool{ 30 | didSet{ 31 | backgroundColor = UIColor.white.withAlphaComponent(isSelected ? 0.1 : 0.2) 32 | } 33 | } 34 | 35 | @available(*, unavailable) 36 | required init?(coder aDecoder: NSCoder) { return nil } 37 | 38 | override init(frame: CGRect) { 39 | super.init(frame: frame) 40 | 41 | setupCell() 42 | setupImageView() 43 | setupLabel() 44 | } 45 | 46 | private func setupCell() { 47 | layer.cornerRadius = 8 48 | backgroundColor = UIColor.white.withAlphaComponent(0.2) 49 | } 50 | 51 | private func setupImageView() { 52 | addSubview(imageView) 53 | 54 | NSLayoutConstraint.activate([ 55 | imageView.centerYAnchor.constraint(equalTo: centerYAnchor), 56 | imageView.heightAnchor.constraint(equalToConstant: frame.height*0.5), 57 | imageView.widthAnchor.constraint(equalToConstant: frame.height*0.5), 58 | imageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12) 59 | ]) 60 | } 61 | 62 | private func setupLabel() { 63 | addSubview(label) 64 | 65 | NSLayoutConstraint.activate([ 66 | label.centerYAnchor.constraint(equalTo: centerYAnchor), 67 | label.heightAnchor.constraint(equalToConstant: 30), 68 | label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), 69 | label.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 20) 70 | ]) 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-40x40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-60x60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "idiom" : "ipad", 53 | "size" : "20x20", 54 | "scale" : "1x" 55 | }, 56 | { 57 | "idiom" : "ipad", 58 | "size" : "20x20", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "idiom" : "ipad", 63 | "size" : "29x29", 64 | "scale" : "1x" 65 | }, 66 | { 67 | "idiom" : "ipad", 68 | "size" : "29x29", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "idiom" : "ipad", 73 | "size" : "40x40", 74 | "scale" : "1x" 75 | }, 76 | { 77 | "idiom" : "ipad", 78 | "size" : "40x40", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "idiom" : "ipad", 83 | "size" : "76x76", 84 | "scale" : "1x" 85 | }, 86 | { 87 | "idiom" : "ipad", 88 | "size" : "76x76", 89 | "scale" : "2x" 90 | }, 91 | { 92 | "idiom" : "ipad", 93 | "size" : "83.5x83.5", 94 | "scale" : "2x" 95 | }, 96 | { 97 | "size" : "1024x1024", 98 | "idiom" : "ios-marketing", 99 | "filename" : "SortingAlgorithmsLogo.001.jpeg", 100 | "scale" : "1x" 101 | } 102 | ], 103 | "info" : { 104 | "version" : 1, 105 | "author" : "xcode" 106 | } 107 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Alt text](https://i.imgur.com/SaWlE8K.png) 2 | 3 | # Sorting Algorithms App 4 | An open source app focused on show in a visual way how sorting algorithms actually works. 5 | 6 | **Available on the app store** 7 | 8 | ![Alt text](https://i.imgur.com/CL9hL95.png) 9 | 10 | ### Do you want to contribute? Check the backlog 11 | 12 | #### // TODO: 13 | - [ ] New algorithms; 14 | - [ ] Control animation speed; 15 | - [ ] Add algorithm details about the selected algorithm; 16 | - [ ] Improve code coverage (unit tests); 17 | - [ ] More features to the backlog :) 18 | 19 | ### Adding a new algorithm 20 | 21 | Create a class implemeting the protocol ```Algorithm```. Following the example for the class ```InsertionSort```, you'd need to set the title of your algorithm, the image (pick a nice logo representing your algorithm:)) and description. In the method ```GenerateSwaps```, add the necessary logic to generate all cell swaps which would be necessary. 22 | 23 | ```Swift 24 | final class InsertionSort: Algorithm { 25 | 26 | final var title: String = "Insertion Sort" 27 | final var image: String = "ic_insertion" 28 | final var description: String = "Insertion Sort Description" 29 | 30 | final func generateSwaps(from list: [Int]) -> [(x0: Int, x1: Int)] { 31 | if list.count == 1 { return [] } 32 | 33 | var array = list 34 | var swaps = [(x0: Int, x1: Int)]() 35 | 36 | // APPEND ALL GENERATED SWAPS TO IT'S ARRAY 37 | 38 | return swaps 39 | } 40 | } 41 | ``` 42 | 43 | ### Update the data source with your new algorithm 44 | 45 | ```Swift 46 | class AlgorithmsListPresenter { 47 | 48 | private weak var view: AlgorithmsListView? 49 | private let router: AlgorithmsListRoutering 50 | 51 | private let dataSource: [Algorithm] = [ 52 | BubbleSort(), 53 | InsertionSort(), 54 | SelectionSort() 55 | ] 56 | ... 57 | } 58 | ``` 59 | 60 | ### Submiting contributions 61 | 62 | Try adding your own solution, feel free to suggest changes on the current code. If you're ready to submit a contribution, create a pull request describing your approach. All contributions are welcome even the small ones. 63 | 64 | ### Contributors 65 | The list of [contributors](https://github.com/victorpanitz/iOS-SortingAlgorithmsApp/graphs/contributors): 66 | 67 | 🇧🇷 - [Victor Panitz Magalhães](https://github.com/victorpanitz) 68 | 69 | 🇮🇳 - [Anantha Krishnan](https://github.com/AnanthaKrish) 70 | 71 | 🇧🇷 - [João Reichert](https://github.com/reeichert) 72 | 73 | 🇨🇳 - [urmyfaith](https://github.com/urmyfaith?tab=repositories) 74 | 75 | 76 | -------------------------------------------------------------------------------- /fastlane/test_output/report.junit: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /SortingAlgorithms/SupportingFiles/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/xcshareddata/xcschemes/SortingAlgorithmsTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /SortingAlgorithmsTests/ModulesTests/AlgorithmsList/AlgorithmsListPresenterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmsListPresenterTests.swift 3 | // SortingAlgorithmsTests 4 | // 5 | // Created by Victor Magalhaes on 07/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SortingAlgorithms 11 | 12 | final class AlgorithmsListPresenterTests: XCTestCase { 13 | 14 | var sut_presenter: AlgorithmsListPresenter! 15 | var view: AlgorithmsListViewSpy! 16 | var router: AlgorithmsListRouteringSpy! 17 | 18 | override func setUp() { 19 | view = AlgorithmsListViewSpy() 20 | router = AlgorithmsListRouteringSpy() 21 | sut_presenter = AlgorithmsListPresenter(router: router) 22 | 23 | sut_presenter.attachView(view) 24 | } 25 | 26 | func test_attachView() { 27 | XCTAssert(view.updateDataSourceCalled == true) 28 | XCTAssert(view.dataSourcePassed!.count == 4) 29 | XCTAssert(view.dataSourcePassed![0] is BubbleSort) 30 | XCTAssert(view.dataSourcePassed![1] is InsertionSort) 31 | XCTAssert(view.dataSourcePassed![2] is SelectionSort) 32 | XCTAssert(view.dataSourcePassed![3] is QuickSort) 33 | } 34 | 35 | func test_viewWillAppear() { 36 | sut_presenter.viewWillAppear() 37 | 38 | XCTAssert(view.setNavigationBarTitleCalled == true) 39 | XCTAssert(view.navigationBarTitlePassed == "Sorting Algorithms") 40 | } 41 | 42 | func test_itemTriggered_bubbleSort() { 43 | sut_presenter.itemTriggered(index: 0) 44 | 45 | XCTAssert(router.navigateToAlgorithmDetailCalled == true) 46 | XCTAssert(router.algorithmPassed is BubbleSort) 47 | } 48 | 49 | func test_itemTriggered_insertionSort() { 50 | sut_presenter.itemTriggered(index: 1) 51 | 52 | XCTAssert(router.navigateToAlgorithmDetailCalled == true) 53 | XCTAssert(router.algorithmPassed is InsertionSort) 54 | } 55 | 56 | func test_itemTriggered_selectionSort() { 57 | sut_presenter.itemTriggered(index: 2) 58 | 59 | XCTAssert(router.navigateToAlgorithmDetailCalled == true) 60 | XCTAssert(router.algorithmPassed is SelectionSort) 61 | } 62 | 63 | func test_itemTriggered_quickSort() { 64 | sut_presenter.itemTriggered(index: 3) 65 | 66 | XCTAssert(router.navigateToAlgorithmDetailCalled == true) 67 | XCTAssert(router.algorithmPassed is QuickSort) 68 | } 69 | 70 | 71 | func test_itemTriggered_invalid_index() { 72 | sut_presenter.itemTriggered(index: 4) 73 | 74 | XCTAssert(router.navigateToAlgorithmDetailCalled == nil) 75 | XCTAssert(router.algorithmPassed == nil) 76 | } 77 | 78 | } 79 | 80 | final class AlgorithmsListViewSpy: AlgorithmsListView { 81 | 82 | var setNavigationBarTitleCalled: Bool? 83 | var navigationBarTitlePassed: String? 84 | var updateDataSourceCalled: Bool? 85 | var dataSourcePassed: [Algorithm]? 86 | 87 | func setNavigationBarTitle(_ text: String) { 88 | setNavigationBarTitleCalled = true 89 | navigationBarTitlePassed = text 90 | } 91 | 92 | func updateDataSource(dataSource: [Algorithm]) { 93 | updateDataSourceCalled = true 94 | dataSourcePassed = dataSource 95 | } 96 | 97 | } 98 | 99 | final class AlgorithmsListRouteringSpy: AlgorithmsListRoutering { 100 | var navigateToAlgorithmDetailCalled: Bool? 101 | var algorithmPassed: Algorithm? 102 | 103 | func navigateToAlgorithmDetail(algorithm: Algorithm) { 104 | navigateToAlgorithmDetailCalled = true 105 | algorithmPassed = algorithm 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/xcshareddata/xcschemes/SortingAlgorithms.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 86 | 92 | 93 | 94 | 95 | 97 | 98 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.0) 5 | addressable (2.8.1) 6 | public_suffix (>= 2.0.2, < 6.0) 7 | atomos (0.1.3) 8 | babosa (1.0.2) 9 | claide (1.0.2) 10 | colored (1.2) 11 | colored2 (3.1.2) 12 | commander-fastlane (4.4.6) 13 | highline (~> 1.7.2) 14 | declarative (0.0.10) 15 | declarative-option (0.1.0) 16 | digest-crc (0.4.1) 17 | domain_name (0.5.20180417) 18 | unf (>= 0.0.5, < 1.0.0) 19 | dotenv (2.7.2) 20 | emoji_regex (1.0.1) 21 | excon (0.63.0) 22 | faraday (0.15.4) 23 | multipart-post (>= 1.2, < 3) 24 | faraday-cookie_jar (0.0.6) 25 | faraday (>= 0.7.4) 26 | http-cookie (~> 1.0.0) 27 | faraday_middleware (0.13.1) 28 | faraday (>= 0.7.4, < 1.0) 29 | fastimage (2.1.5) 30 | fastlane (2.120.0) 31 | CFPropertyList (>= 2.3, < 4.0.0) 32 | addressable (>= 2.3, < 3.0.0) 33 | babosa (>= 1.0.2, < 2.0.0) 34 | bundler (>= 1.12.0, < 3.0.0) 35 | colored 36 | commander-fastlane (>= 4.4.6, < 5.0.0) 37 | dotenv (>= 2.1.1, < 3.0.0) 38 | emoji_regex (>= 0.1, < 2.0) 39 | excon (>= 0.45.0, < 1.0.0) 40 | faraday (~> 0.9) 41 | faraday-cookie_jar (~> 0.0.6) 42 | faraday_middleware (~> 0.9) 43 | fastimage (>= 2.1.0, < 3.0.0) 44 | gh_inspector (>= 1.1.2, < 2.0.0) 45 | google-api-client (>= 0.21.2, < 0.24.0) 46 | google-cloud-storage (>= 1.15.0, < 2.0.0) 47 | highline (>= 1.7.2, < 2.0.0) 48 | json (< 3.0.0) 49 | mini_magick (~> 4.5.1) 50 | multi_json 51 | multi_xml (~> 0.5) 52 | multipart-post (~> 2.0.0) 53 | plist (>= 3.1.0, < 4.0.0) 54 | public_suffix (~> 2.0.0) 55 | rubyzip (>= 1.2.2, < 2.0.0) 56 | security (= 0.1.3) 57 | simctl (~> 1.6.3) 58 | slack-notifier (>= 2.0.0, < 3.0.0) 59 | terminal-notifier (>= 2.0.0, < 3.0.0) 60 | terminal-table (>= 1.4.5, < 2.0.0) 61 | tty-screen (>= 0.6.3, < 1.0.0) 62 | tty-spinner (>= 0.8.0, < 1.0.0) 63 | word_wrap (~> 1.0.0) 64 | xcodeproj (>= 1.8.1, < 2.0.0) 65 | xcpretty (~> 0.3.0) 66 | xcpretty-travis-formatter (>= 0.0.3) 67 | gh_inspector (1.1.3) 68 | google-api-client (0.23.9) 69 | addressable (~> 2.5, >= 2.5.1) 70 | googleauth (>= 0.5, < 0.7.0) 71 | httpclient (>= 2.8.1, < 3.0) 72 | mime-types (~> 3.0) 73 | representable (~> 3.0) 74 | retriable (>= 2.0, < 4.0) 75 | signet (~> 0.9) 76 | google-cloud-core (1.3.0) 77 | google-cloud-env (~> 1.0) 78 | google-cloud-env (1.0.5) 79 | faraday (~> 0.11) 80 | google-cloud-storage (1.16.0) 81 | digest-crc (~> 0.4) 82 | google-api-client (~> 0.23) 83 | google-cloud-core (~> 1.2) 84 | googleauth (>= 0.6.2, < 0.10.0) 85 | googleauth (0.6.7) 86 | faraday (~> 0.12) 87 | jwt (>= 1.4, < 3.0) 88 | memoist (~> 0.16) 89 | multi_json (~> 1.11) 90 | os (>= 0.9, < 2.0) 91 | signet (~> 0.7) 92 | highline (1.7.10) 93 | http-cookie (1.0.3) 94 | domain_name (~> 0.5) 95 | httpclient (2.8.3) 96 | json (2.2.0) 97 | jwt (2.1.0) 98 | memoist (0.16.0) 99 | mime-types (3.2.2) 100 | mime-types-data (~> 3.2015) 101 | mime-types-data (3.2019.0331) 102 | mini_magick (4.5.1) 103 | multi_json (1.13.1) 104 | multi_xml (0.6.0) 105 | multipart-post (2.0.0) 106 | nanaimo (0.2.6) 107 | naturally (2.2.0) 108 | os (1.0.0) 109 | plist (3.5.0) 110 | public_suffix (2.0.5) 111 | representable (3.0.4) 112 | declarative (< 0.1.0) 113 | declarative-option (< 0.2.0) 114 | uber (< 0.2.0) 115 | retriable (3.1.2) 116 | rouge (2.0.7) 117 | rubyzip (1.2.2) 118 | security (0.1.3) 119 | signet (0.11.0) 120 | addressable (~> 2.3) 121 | faraday (~> 0.9) 122 | jwt (>= 1.5, < 3.0) 123 | multi_json (~> 1.10) 124 | simctl (1.6.5) 125 | CFPropertyList 126 | naturally 127 | slack-notifier (2.3.2) 128 | terminal-notifier (2.0.0) 129 | terminal-table (1.8.0) 130 | unicode-display_width (~> 1.1, >= 1.1.1) 131 | tty-cursor (0.6.1) 132 | tty-screen (0.6.5) 133 | tty-spinner (0.9.0) 134 | tty-cursor (~> 0.6.0) 135 | uber (0.1.0) 136 | unf (0.1.4) 137 | unf_ext 138 | unf_ext (0.0.7.5) 139 | unicode-display_width (1.5.0) 140 | word_wrap (1.0.0) 141 | xcodeproj (1.8.2) 142 | CFPropertyList (>= 2.3.3, < 4.0) 143 | atomos (~> 0.1.3) 144 | claide (>= 1.0.2, < 2.0) 145 | colored2 (~> 3.1) 146 | nanaimo (~> 0.2.6) 147 | xcpretty (0.3.0) 148 | rouge (~> 2.0.7) 149 | xcpretty-travis-formatter (1.0.0) 150 | xcpretty (~> 0.2, >= 0.0.7) 151 | 152 | PLATFORMS 153 | ruby 154 | 155 | DEPENDENCIES 156 | fastlane 157 | 158 | BUNDLED WITH 159 | 2.0.1 160 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmsList/AlgorithmsListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 02/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class AlgorithmsListViewController: UIViewController { 12 | 13 | private lazy var collectionView: UICollectionView = { 14 | let layout = UICollectionViewFlowLayout() 15 | layout.scrollDirection = .vertical 16 | 17 | let collection = UICollectionView(frame: .zero, collectionViewLayout: layout) 18 | collection.register(AlgorithmsListCell.self, forCellWithReuseIdentifier: "cell") 19 | collection.backgroundColor = UIColor.clear 20 | collection.contentMode = .scaleAspectFill 21 | collection.isUserInteractionEnabled = true 22 | collection.isScrollEnabled = true 23 | collection.dataSource = self 24 | collection.delegate = self 25 | collection.translatesAutoresizingMaskIntoConstraints = false 26 | 27 | return collection 28 | }() 29 | 30 | private var dataSource = [Algorithm]() 31 | private let presenter: AlgorithmsListPresenter 32 | 33 | init(presenter: AlgorithmsListPresenter) { 34 | self.presenter = presenter 35 | 36 | super.init(nibName: nil, bundle: nil) 37 | } 38 | 39 | @available(*, unavailable) 40 | required init?(coder aDecoder: NSCoder) { return nil } 41 | 42 | override func viewDidLoad() { 43 | super.viewDidLoad() 44 | 45 | view.backgroundColor = .black 46 | 47 | setupCollectionView() 48 | setupNavigationBar() 49 | 50 | presenter.attachView(self) 51 | } 52 | 53 | override func viewWillAppear(_ animated: Bool) { 54 | super.viewWillAppear(animated) 55 | 56 | self.navigationController?.navigationBar.prefersLargeTitles = true 57 | 58 | presenter.viewWillAppear() 59 | } 60 | 61 | private func setupNavigationBar() { 62 | navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) 63 | navigationController?.navigationBar.barStyle = UIBarStyle.black 64 | navigationController?.navigationBar.tintColor = .white 65 | navigationController?.navigationBar.barTintColor = .black 66 | navigationController?.interactivePopGestureRecognizer?.isEnabled = false 67 | navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] 68 | } 69 | 70 | private func setupCollectionView() { 71 | view.addSubview(collectionView) 72 | 73 | NSLayoutConstraint.activate([ 74 | collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), 75 | collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), 76 | collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), 77 | collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), 78 | ]) 79 | } 80 | } 81 | 82 | extension AlgorithmsListViewController: AlgorithmsListView { 83 | func updateDataSource(dataSource: [Algorithm]) { 84 | self.dataSource = dataSource 85 | collectionView.reloadData() 86 | } 87 | 88 | func setNavigationBarTitle(_ text: String) { 89 | navigationItem.title = text 90 | } 91 | } 92 | 93 | extension AlgorithmsListViewController: UICollectionViewDelegate { 94 | func collectionView( 95 | _ collectionView: UICollectionView, 96 | didSelectItemAt indexPath: IndexPath) { 97 | collectionView.deselectItem(at: indexPath, animated: true) 98 | presenter.itemTriggered(index: indexPath.row) 99 | } 100 | } 101 | 102 | extension AlgorithmsListViewController: UICollectionViewDataSource { 103 | 104 | func collectionView( 105 | _ collectionView: UICollectionView, 106 | numberOfItemsInSection section: Int) -> Int { 107 | 108 | return dataSource.count 109 | } 110 | 111 | func collectionView( 112 | _ collectionView: UICollectionView, 113 | cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 114 | 115 | guard let cell = collectionView.dequeue("cell", for: indexPath) as? AlgorithmsListCell 116 | else { return UICollectionViewCell()} 117 | 118 | cell.imageView.image = UIImage(named: dataSource[indexPath.row].image) 119 | cell.label.text = dataSource[indexPath.row].title 120 | 121 | return cell 122 | } 123 | 124 | func collectionView( 125 | _ collectionView: UICollectionView, 126 | layout collectionViewLayout: UICollectionViewLayout, 127 | minimumLineSpacingForSectionAt section: Int) -> CGFloat { 128 | 129 | return 12 130 | } 131 | 132 | func collectionView( 133 | _ collectionView: UICollectionView, 134 | layout collectionViewLayout: UICollectionViewLayout, 135 | sizeForItemAt indexPath: IndexPath) -> CGSize { 136 | 137 | return CGSize(width: self.view.frame.width * 0.9 , height: self.view.frame.height * 0.08) 138 | } 139 | 140 | } 141 | 142 | extension AlgorithmsListViewController: UICollectionViewDelegateFlowLayout {} 143 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/AlgorithmDetail/AlgorithmDetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmDetailViewController.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 03/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | final class AlgorithmDetailViewController: UIViewController { 13 | 14 | lazy var closeButton: UIBarButtonItem = { 15 | var rightButton = UIBarButtonItem( 16 | barButtonSystemItem: UIBarButtonItem.SystemItem.stop, 17 | target: self, 18 | action: #selector(closeButtonDidTouchUpInside) 19 | ) 20 | return rightButton 21 | }() 22 | 23 | lazy var restartButton: UIBarButtonItem = { 24 | let restartButton = UIBarButtonItem( 25 | barButtonSystemItem: .refresh, 26 | target: self, 27 | action: #selector(restartButtonDidTouchUpInside)) 28 | restartButton.isEnabled = false 29 | return restartButton 30 | }() 31 | 32 | lazy var collectionView: UICollectionView = { 33 | let layout = UICollectionViewFlowLayout() 34 | layout.scrollDirection = .vertical 35 | 36 | let collection = UICollectionView(frame: .zero, collectionViewLayout: layout) 37 | collection.register(AlgorithmDetailCell.self, forCellWithReuseIdentifier: "cell") 38 | collection.backgroundColor = UIColor.clear 39 | collection.contentMode = .scaleAspectFill 40 | collection.dataSource = self 41 | collection.translatesAutoresizingMaskIntoConstraints = false 42 | collection.contentInset = UIEdgeInsets(top: 30, left: 20, bottom: 30, right: 20) 43 | 44 | return collection 45 | }() 46 | 47 | private var datasource = [Int]() 48 | 49 | private let presenter: AlgorithmDetailPresenter 50 | 51 | init(presenter: AlgorithmDetailPresenter) { 52 | self.presenter = presenter 53 | 54 | super.init(nibName: nil, bundle: nil) 55 | } 56 | 57 | @available(*, unavailable) 58 | required init?(coder aDecoder: NSCoder) { return nil } 59 | 60 | override func viewDidLoad() { 61 | super.viewDidLoad() 62 | 63 | view.backgroundColor = .black 64 | 65 | setupNavigationBar() 66 | setupCollectionView() 67 | 68 | presenter.attachView(self) 69 | } 70 | 71 | override func viewDidAppear(_ animated: Bool) { 72 | super.viewDidAppear(animated) 73 | 74 | presenter.viewDidAppear() 75 | collectionView.reloadData() 76 | } 77 | 78 | private func setupNavigationBar() { 79 | navigationController?.navigationBar.prefersLargeTitles = false 80 | 81 | self.navigationItem.rightBarButtonItems = [ 82 | restartButton, 83 | closeButton 84 | ] 85 | } 86 | 87 | private func setupCollectionView() {setupNavigationBar() 88 | view.addSubview(collectionView) 89 | 90 | NSLayoutConstraint.activate([ 91 | collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), 92 | collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), 93 | collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), 94 | collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), 95 | ]) 96 | } 97 | 98 | @objc private func closeButtonDidTouchUpInside() { 99 | presenter.closeButtonTriggered() 100 | } 101 | 102 | @objc private func restartButtonDidTouchUpInside() { 103 | presenter.restartButtonTriggered() 104 | } 105 | } 106 | 107 | extension AlgorithmDetailViewController: AlgorithmDetailView { 108 | 109 | func toggleRestartButton(_ isEnable: Bool) { 110 | restartButton.isEnabled = isEnable 111 | } 112 | 113 | func setNavigationBarTitle(_ text: String) { 114 | navigationItem.title = text 115 | } 116 | 117 | func updateDataSource(_ datasource: [Int]) { 118 | self.datasource = datasource 119 | } 120 | 121 | func updateDataSourceAndReloadData(_ datasource: [Int]) { 122 | self.datasource = datasource 123 | self.collectionView.reloadData() 124 | } 125 | 126 | func swapCell(x0: Int, x1: Int) { 127 | UIView.animate(withDuration: 0.8, animations: { 128 | self.collectionView.swap(x0, x1, completion: { [weak self] (_) in 129 | self?.presenter.swapDidComplete() 130 | }) 131 | }) 132 | } 133 | 134 | } 135 | 136 | extension AlgorithmDetailViewController: UICollectionViewDataSource { 137 | 138 | func collectionView( 139 | _ collectionView: UICollectionView, 140 | numberOfItemsInSection section: Int) -> Int { 141 | 142 | return datasource.count 143 | } 144 | 145 | func collectionView( 146 | _ collectionView: UICollectionView, 147 | cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 148 | 149 | guard let cell = collectionView.dequeue("cell", for: indexPath) as? AlgorithmDetailCell 150 | else { return UICollectionViewCell() } 151 | 152 | cell.label.text = "\(datasource[indexPath.row])" 153 | 154 | return cell 155 | } 156 | 157 | func collectionView( 158 | _ collectionView: UICollectionView, 159 | layout collectionViewLayout: UICollectionViewLayout, 160 | minimumLineSpacingForSectionAt section: Int) -> CGFloat { 161 | 162 | return 12 163 | } 164 | 165 | func collectionView( 166 | _ collectionView: UICollectionView, 167 | layout collectionViewLayout: UICollectionViewLayout, 168 | sizeForItemAt indexPath: IndexPath) -> CGSize { 169 | 170 | return CGSize(width: self.view.frame.width * 0.1 , height: self.view.frame.width * 0.1) 171 | } 172 | 173 | } 174 | 175 | extension AlgorithmDetailViewController: UICollectionViewDelegateFlowLayout {} 176 | -------------------------------------------------------------------------------- /SortingAlgorithmsTests/ModulesTests/AlgorithmDetail/AlgorithmDetailPresenterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmDetailPresenterTests.swift 3 | // SortingAlgorithmsTests 4 | // 5 | // Created by Victor on 08/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SortingAlgorithms 11 | 12 | final class AlgorithmsDetailPresenterTests: XCTestCase { 13 | 14 | private var sut_presenter: AlgorithmDetailPresenter! 15 | private var view: AlgorithmDetailViewSpy! 16 | private var router: AlgorithmDetailRouteringSpy! 17 | private var algorithm: AlgorithmSpy! 18 | 19 | override func setUp() { 20 | view = AlgorithmDetailViewSpy() 21 | router = AlgorithmDetailRouteringSpy() 22 | algorithm = AlgorithmSpy() 23 | sut_presenter = AlgorithmDetailPresenter(router: router, algorithm: algorithm, datasource: [1,3,2,5,4]) 24 | sut_presenter.attachView(view) 25 | } 26 | 27 | func test_attachView() { 28 | XCTAssertEqual(view.setNavigationBarTitleCalled, true) 29 | XCTAssertEqual(view.navigationBarTitlePassed, "algorithm title value") 30 | XCTAssertEqual(view.updateDataSourceCalled , true) 31 | XCTAssertEqual(view.reloadDataCalled, false) 32 | XCTAssertEqual(view.dataSourcePassed!.count, 5) 33 | XCTAssertEqual(view.dataSourcePassed![0], 1) 34 | XCTAssertEqual(view.dataSourcePassed![1], 3) 35 | XCTAssertEqual(view.dataSourcePassed![2], 2) 36 | XCTAssertEqual(view.dataSourcePassed![3], 5) 37 | XCTAssertEqual(view.dataSourcePassed![4], 4) 38 | } 39 | 40 | func test_viewDidAppear() { 41 | sut_presenter.viewDidAppear() 42 | 43 | XCTAssertEqual(view.updateDataSourceCalled, true) 44 | XCTAssertEqual(view.reloadDataCalled, false) 45 | XCTAssertEqual(view.dataSourcePassed!.count, 5) 46 | XCTAssertEqual(view.dataSourcePassed![0], 3) 47 | XCTAssertEqual(view.dataSourcePassed![1], 1) 48 | XCTAssertEqual(view.dataSourcePassed![2], 2) 49 | XCTAssertEqual(view.dataSourcePassed![3], 5) 50 | XCTAssertEqual(view.dataSourcePassed![4], 4) 51 | 52 | XCTAssertEqual(view.swapCellCalled, true) 53 | XCTAssertEqual(view.swaps.count, 1) 54 | XCTAssertEqual(view.swaps[0].x0, 0) 55 | XCTAssertEqual(view.swaps[0].x1, 1) 56 | } 57 | 58 | func test_swapDidComplete() { 59 | sut_presenter.viewDidAppear() 60 | sut_presenter.swapDidComplete() 61 | 62 | XCTAssertEqual(view.updateDataSourceCalled, true) 63 | XCTAssertEqual(view.reloadDataCalled, false) 64 | XCTAssertEqual(view.dataSourcePassed!.count, 5) 65 | XCTAssertEqual(view.dataSourcePassed![0], 3) 66 | XCTAssertEqual(view.dataSourcePassed![1], 1) 67 | XCTAssertEqual(view.dataSourcePassed![2], 5) 68 | XCTAssertEqual(view.dataSourcePassed![3], 2) 69 | XCTAssertEqual(view.dataSourcePassed![4], 4) 70 | 71 | XCTAssertEqual(view.swapCellCalled, true) 72 | XCTAssertEqual(view.swaps.count, 2) 73 | XCTAssertEqual(view.swaps[0].x0, 0) 74 | XCTAssertEqual(view.swaps[0].x1, 1) 75 | XCTAssertEqual(view.swaps[1].x0, 2) 76 | XCTAssertEqual(view.swaps[1].x1, 3) 77 | } 78 | 79 | func test_closeButtonTriggered() { 80 | sut_presenter.closeButtonTriggered() 81 | 82 | XCTAssertEqual(router.dismissCalled, true) 83 | } 84 | 85 | func test_restartButtonTriggered() { 86 | sut_presenter.restartButtonTriggered() 87 | 88 | XCTAssertEqual(view.restartButtonIsEnable, false) 89 | XCTAssertEqual(view.updateDataSourceCalled, true) 90 | XCTAssertEqual(view.reloadDataCalled, true) 91 | XCTAssertEqual(view.dataSourcePassed!.count, 5) 92 | XCTAssertEqual(view.dataSourcePassed![0], 1) 93 | XCTAssertEqual(view.dataSourcePassed![1], 3) 94 | XCTAssertEqual(view.dataSourcePassed![2], 2) 95 | XCTAssertEqual(view.dataSourcePassed![3], 5) 96 | XCTAssertEqual(view.dataSourcePassed![4], 4) 97 | } 98 | 99 | } 100 | 101 | final class AlgorithmDetailViewSpy: AlgorithmDetailView { 102 | 103 | var updateDataSourceCalled: Bool? 104 | var reloadDataCalled: Bool? 105 | var swapCellCalled: Bool? 106 | var toggleRestartButtonCalled: Bool? 107 | var restartButtonIsEnable: Bool? 108 | var setNavigationBarTitleCalled: Bool? 109 | var dataSourcePassed: [Int]? 110 | var swaps = [(x0: Int, x1: Int)]() 111 | var x0IndexPassed: Int? 112 | var x1IndexPassed: Int? 113 | var navigationBarTitlePassed: String? 114 | 115 | func updateDataSource(_ datasource: [Int]) { 116 | updateDataSourceCalled = true 117 | reloadDataCalled = false 118 | dataSourcePassed = datasource 119 | } 120 | 121 | func swapCell(x0: Int, x1: Int) { 122 | swapCellCalled = true 123 | swaps.append((x0: x0, x1: x1)) 124 | } 125 | 126 | func setNavigationBarTitle(_ text: String) { 127 | setNavigationBarTitleCalled = true 128 | navigationBarTitlePassed = text 129 | } 130 | 131 | func updateDataSourceAndReloadData(_ datasource: [Int]) { 132 | updateDataSourceCalled = true 133 | reloadDataCalled = true 134 | dataSourcePassed = datasource 135 | } 136 | 137 | func toggleRestartButton(_ isEnable: Bool) { 138 | toggleRestartButtonCalled = true 139 | restartButtonIsEnable = isEnable 140 | } 141 | 142 | } 143 | 144 | final class AlgorithmDetailRouteringSpy: AlgorithmDetailRoutering { 145 | 146 | var dismissCalled: Bool? 147 | 148 | func dismiss() { 149 | dismissCalled = true 150 | } 151 | 152 | } 153 | 154 | final class AlgorithmSpy: Algorithm { 155 | var title: String = "algorithm title value" 156 | var description: String = "algorithm description value" 157 | var image: String = "algorithm image value" 158 | 159 | func generateSwaps(from list: [Int]) -> [(x0: Int, x1: Int)] { 160 | return [ 161 | (x0: 0, x1: 1), 162 | (x0: 2, x1: 3), 163 | (x0: 4, x1: 5) 164 | ] 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/xcuserdata/VictorMagalhaes.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 56 | 68 | 69 | 70 | 72 | 84 | 85 | 86 | 88 | 100 | 101 | 102 | 104 | 116 | 117 | 118 | 120 | 132 | 133 | 134 | 136 | 148 | 149 | 150 | 152 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /SortingAlgorithms/Scenes/DataSourceInput/DataSourceViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmInsertionViewController.swift 3 | // SortingAlgorithms 4 | // 5 | // Created by Victor on 05/04/19. 6 | // Copyright © 2019 Victor. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | final class DataSourceViewController: UIViewController { 13 | 14 | private lazy var inputField: PaddedTextField = { 15 | let textField = PaddedTextField() 16 | textField.textColor = .black 17 | textField.font = UIFont(name: "Avenir-Light", size: 40) 18 | textField.backgroundColor = .white 19 | textField.delegate = self 20 | textField.keyboardType = .numberPad 21 | textField.layer.shadowRadius = 10 22 | textField.layer.shadowOpacity = 0.5 23 | textField.translatesAutoresizingMaskIntoConstraints = false 24 | 25 | return textField 26 | }() 27 | 28 | private let addButton: UIButton = { 29 | let button = UIButton(type: .system) 30 | button.titleLabel?.font = UIFont(name: "Avenir", size: 20) 31 | button.setTitleColor(#colorLiteral(red: 0, green: 0.9768045545, blue: 0, alpha: 1), for: .normal) 32 | button.setTitle("Add", for: .normal) 33 | button.layer.cornerRadius = 8 34 | button.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner] 35 | button.translatesAutoresizingMaskIntoConstraints = false 36 | button.backgroundColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1).withAlphaComponent(0.3) 37 | 38 | return button 39 | }() 40 | 41 | private let removeButton: UIButton = { 42 | let button = UIButton(type: .system) 43 | button.titleLabel?.font = UIFont(name: "Avenir", size: 20) 44 | button.setTitleColor(#colorLiteral(red: 0.8459790349, green: 0.2873021364, blue: 0.2579272389, alpha: 1), for: .normal) 45 | button.setTitle("Remove", for: .normal) 46 | button.layer.cornerRadius = 8 47 | button.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner] 48 | button.translatesAutoresizingMaskIntoConstraints = false 49 | button.backgroundColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1).withAlphaComponent(0.3) 50 | 51 | return button 52 | }() 53 | 54 | private let arrayLabel: UILabel = { 55 | let label = UILabel() 56 | label.font = UIFont(name: "Avenir", size: 14) 57 | label.textColor = .white 58 | label.numberOfLines = 0 59 | label.textAlignment = .center 60 | label.translatesAutoresizingMaskIntoConstraints = false 61 | 62 | return label 63 | }() 64 | 65 | private let addSampleButton: UIButton = { 66 | let button = UIButton(type: .system) 67 | button.titleLabel?.font = UIFont(name: "Avenir", size: 20) 68 | button.setTitleColor(#colorLiteral(red: 0, green: 0.9768045545, blue: 0, alpha: 1), for: .normal) 69 | button.setTitle("Sample Array", for: .normal) 70 | button.layer.cornerRadius = 8 71 | button.translatesAutoresizingMaskIntoConstraints = false 72 | button.backgroundColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1).withAlphaComponent(0.3) 73 | 74 | return button 75 | }() 76 | 77 | let presenter: DataSourcePresenter 78 | 79 | init(presenter: DataSourcePresenter) { 80 | self.presenter = presenter 81 | 82 | super.init(nibName: nil, bundle: nil) 83 | } 84 | 85 | @available(*, unavailable) 86 | required init?(coder aDecoder: NSCoder) { return nil } 87 | 88 | override func viewDidLoad() { 89 | super.viewDidLoad() 90 | 91 | view.backgroundColor = .black 92 | 93 | setupNavigationBar() 94 | 95 | setupInputField() 96 | setupAddButton() 97 | setupRemoveButton() 98 | setupArrayLabel() 99 | setupAddSampleButton() 100 | 101 | presenter.attachView(self) 102 | } 103 | 104 | override func viewDidAppear(_ animated: Bool) { 105 | super.viewDidAppear(animated) 106 | 107 | presenter.viewDidAppear() 108 | } 109 | 110 | private func setupNavigationBar() { 111 | navigationController?.navigationBar.prefersLargeTitles = false 112 | let rightButton = UIBarButtonItem(title: "Run", style: .done, target: self, action: #selector(runTouchUpInside)) 113 | self.navigationItem.rightBarButtonItem = rightButton 114 | } 115 | 116 | private func setupInputField(){ 117 | view.addSubview(inputField) 118 | 119 | NSLayoutConstraint.activate([ 120 | inputField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 60), 121 | inputField.centerXAnchor.constraint(equalTo: view.centerXAnchor), 122 | inputField.widthAnchor.constraint(equalToConstant: view.frame.width*0.4), 123 | inputField.heightAnchor.constraint(equalToConstant: view.frame.width*0.3), 124 | ]) 125 | 126 | inputField.becomeFirstResponder() 127 | } 128 | 129 | private func setupArrayLabel() { 130 | view.addSubview(arrayLabel) 131 | 132 | NSLayoutConstraint.activate([ 133 | arrayLabel.topAnchor.constraint(equalTo: inputField.bottomAnchor, constant: 12), 134 | arrayLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24), 135 | arrayLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24), 136 | arrayLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 14) 137 | ]) 138 | } 139 | 140 | private func setupAddButton() { 141 | view.addSubview(addButton) 142 | 143 | NSLayoutConstraint.activate([ 144 | addButton.heightAnchor.constraint(equalToConstant: view.frame.width*0.3), 145 | addButton.leadingAnchor.constraint(equalTo: inputField.trailingAnchor), 146 | addButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -12), 147 | addButton.centerYAnchor.constraint(equalTo: inputField.centerYAnchor) 148 | ]) 149 | 150 | addButton.addTarget(self, action: #selector(addButtonTouchUpInside), for: .touchUpInside) 151 | } 152 | 153 | private func setupRemoveButton() { 154 | view.addSubview(removeButton) 155 | 156 | NSLayoutConstraint.activate([ 157 | removeButton.heightAnchor.constraint(equalToConstant: view.frame.width*0.3), 158 | removeButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 12), 159 | removeButton.trailingAnchor.constraint(equalTo: inputField.leadingAnchor), 160 | removeButton.centerYAnchor.constraint(equalTo: inputField.centerYAnchor) 161 | ]) 162 | 163 | removeButton.addTarget(self, action: #selector(removeButtonTouchUpInside), for: .touchUpInside) 164 | } 165 | 166 | private func setupAddSampleButton() { 167 | view.addSubview(addSampleButton) 168 | 169 | NSLayoutConstraint.activate([ 170 | addSampleButton.topAnchor.constraint(equalTo: arrayLabel.bottomAnchor, constant: 20.0), 171 | addSampleButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), 172 | addSampleButton.widthAnchor.constraint(equalToConstant: 140.0), 173 | addSampleButton.heightAnchor.constraint(equalToConstant: 40.0) 174 | ]) 175 | 176 | addSampleButton.addTarget(self, action: #selector(addSampleArrayTouchUpInside), for: .touchUpInside) 177 | } 178 | 179 | @objc private func runTouchUpInside() { 180 | presenter.runTriggered() 181 | } 182 | 183 | @objc private func addButtonTouchUpInside() { 184 | presenter.addButtonTriggered() 185 | } 186 | 187 | @objc private func removeButtonTouchUpInside() { 188 | presenter.removeButtonTriggered() 189 | } 190 | 191 | @objc private func addSampleArrayTouchUpInside() { 192 | presenter.addSampleButtonTrigerred() 193 | } 194 | 195 | } 196 | 197 | extension DataSourceViewController: DataSourceView { 198 | 199 | func clearInputField() { 200 | inputField.text = "" 201 | } 202 | 203 | func updateArray(_ text: String) { 204 | arrayLabel.text = text 205 | } 206 | 207 | func setNavigationBarTitle(_ text: String) { 208 | navigationItem.title = text 209 | } 210 | } 211 | 212 | extension DataSourceViewController: UITextFieldDelegate { 213 | 214 | func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { 215 | presenter.inputDidChange(textField.text ?? "") 216 | 217 | return true 218 | } 219 | 220 | func textField( 221 | _ textField: UITextField, 222 | shouldChangeCharactersIn range: NSRange, 223 | replacementString string: String) -> Bool { 224 | 225 | guard ((textField.text ?? "") + string).count > 5 else { 226 | presenter.inputDidChange((textField.text ?? "") + string) 227 | return true 228 | } 229 | 230 | return false 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /fastlane/test_output/report.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test Results | xcpretty 6 | 61 | 105 | 106 | 107 |
108 |
109 |

Test Results

110 |
111 |
112 |
113 |

22 tests

114 | 115 |
116 |
117 | AllFailingPassing 118 |
119 |
120 |
121 |
122 | 123 | 124 |
125 |
126 |

SortingAlgorithmsTests.AlgorithmsDetailPresenterTests

127 |
128 |
129 | 130 | 131 | 132 | 133 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 171 | 172 | 173 | 174 | 175 |
134 | 135 |

0.002s

136 | 137 |

test_attachView

145 | 146 |

0.001s

147 | 148 |

test_closeButtonTriggered

156 | 157 |

0.000s

158 | 159 |

test_swapDidComplete

167 | 168 |

0.000s

169 | 170 |

test_viewDidAppear

176 |
177 |
178 | 179 | 180 |
181 |
182 |

SortingAlgorithmsTests.AlgorithmsListPresenterTests

183 |
184 |
185 | 186 | 187 | 188 | 189 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 249 | 250 | 251 | 252 | 253 |
190 | 191 |

0.001s

192 | 193 |

test_attachView

201 | 202 |

0.000s

203 | 204 |

test_itemTriggered_bubbleSort

212 | 213 |

0.000s

214 | 215 |

test_itemTriggered_insertionSort

223 | 224 |

0.001s

225 | 226 |

test_itemTriggered_invalid_index

234 | 235 |

0.001s

236 | 237 |

test_itemTriggered_selectionSort

245 | 246 |

0.001s

247 | 248 |

test_viewWillAppear

254 |
255 |
256 | 257 | 258 |
259 |
260 |

SortingAlgorithmsTests.BubbleSortTests

261 |
262 |
263 | 264 | 265 | 266 | 267 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 305 | 306 | 307 | 308 | 309 |
268 | 269 |

0.001s

270 | 271 |

test_BubbleSort_already_sorted

279 | 280 |

0.000s

281 | 282 |

test_BubbleSort_equal_values

290 | 291 |

0.001s

292 | 293 |

test_BubbleSort_non_sorted

301 | 302 |

0.001s

303 | 304 |

test_BubbleSort_swap_data_source

310 |
311 |
312 | 313 | 314 |
315 |
316 |

SortingAlgorithmsTests.InsertionSortTests

317 |
318 |
319 | 320 | 321 | 322 | 323 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 361 | 362 | 363 | 364 | 365 |
324 | 325 |

0.001s

326 | 327 |

test_InsertionSort_already_sorted

335 | 336 |

0.001s

337 | 338 |

test_InsertionSort_equal_values

346 | 347 |

0.001s

348 | 349 |

test_InsertionSort_non_sorted

357 | 358 |

0.001s

359 | 360 |

test_InsertionSort_swap_data_source

366 |
367 |
368 | 369 | 370 |
371 |
372 |

SortingAlgorithmsTests.SelectionSortTests

373 |
374 |
375 | 376 | 377 | 378 | 379 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 417 | 418 | 419 | 420 | 421 |
380 | 381 |

0.001s

382 | 383 |

test_SelectionSort_already_sorted

391 | 392 |

0.000s

393 | 394 |

test_SelectionSort_equal_values

402 | 403 |

0.001s

404 | 405 |

test_SelectionSort_non_sorted

413 | 414 |

0.000s

415 | 416 |

test_SelectionSort_swap_data_source

422 |
423 |
424 | 425 |
426 | 427 | 428 | 429 | -------------------------------------------------------------------------------- /SortingAlgorithms.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 147EBB4E22A2196A00D19988 /* QuickSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147EBB4D22A2196A00D19988 /* QuickSort.swift */; }; 11 | 14E5F58322A46133008537F5 /* QuickSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14E5F58222A46133008537F5 /* QuickSortTests.swift */; }; 12 | 712E1385225585B100EFBAC9 /* AlgorithmsListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 712E1384225585B100EFBAC9 /* AlgorithmsListProtocols.swift */; }; 13 | 712E13872255874B00EFBAC9 /* AlgorithmsListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 712E13862255874B00EFBAC9 /* AlgorithmsListPresenter.swift */; }; 14 | 712E138B22558AE200EFBAC9 /* UICollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 712E138A22558AE200EFBAC9 /* UICollectionViewCell.swift */; }; 15 | 712E138D22559D9600EFBAC9 /* AlgorithmsListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 712E138C22559D9600EFBAC9 /* AlgorithmsListRouter.swift */; }; 16 | 712E138F2258F09800EFBAC9 /* AlgorithmDetailRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 712E138E2258F09800EFBAC9 /* AlgorithmDetailRouter.swift */; }; 17 | 716548852253DE8C009C41DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548842253DE8C009C41DD /* AppDelegate.swift */; }; 18 | 716548872253DE8C009C41DD /* AlgorithmsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548862253DE8C009C41DD /* AlgorithmsListViewController.swift */; }; 19 | 7165488C2253DE8D009C41DD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7165488B2253DE8D009C41DD /* Assets.xcassets */; }; 20 | 7165488F2253DE8D009C41DD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7165488D2253DE8D009C41DD /* LaunchScreen.storyboard */; }; 21 | 7165489A2253DE8D009C41DD /* BubbleSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548992253DE8D009C41DD /* BubbleSortTests.swift */; }; 22 | 716548AA2254EB7A009C41DD /* AlgorithmDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548A92254EB7A009C41DD /* AlgorithmDetailViewController.swift */; }; 23 | 716548AC2254EDE7009C41DD /* Algorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548AB2254EDE7009C41DD /* Algorithm.swift */; }; 24 | 716548AE2254EED8009C41DD /* BubbleSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548AD2254EED8009C41DD /* BubbleSort.swift */; }; 25 | 716548B022554791009C41DD /* InsertionSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548AF22554791009C41DD /* InsertionSort.swift */; }; 26 | 716548B222554898009C41DD /* AlgorithmDetailPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548B122554898009C41DD /* AlgorithmDetailPresenter.swift */; }; 27 | 716548B4225548B7009C41DD /* AlgorithmDetailProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548B3225548B7009C41DD /* AlgorithmDetailProtocol.swift */; }; 28 | 716548B622554CEC009C41DD /* AlgorithmsListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548B522554CEC009C41DD /* AlgorithmsListCell.swift */; }; 29 | 716548B822554DDD009C41DD /* AlgorithmDetailCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548B722554DDD009C41DD /* AlgorithmDetailCell.swift */; }; 30 | 716548BA225551E6009C41DD /* SelectionSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716548B9225551E6009C41DD /* SelectionSort.swift */; }; 31 | 716E72E7225AD4D000E436CA /* AlgorithmsListPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716E72E6225AD4D000E436CA /* AlgorithmsListPresenterTests.swift */; }; 32 | 717844922257963400809DD8 /* InsertionSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717844912257963400809DD8 /* InsertionSortTests.swift */; }; 33 | 717844942257964000809DD8 /* SelectionSortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717844932257964000809DD8 /* SelectionSortTests.swift */; }; 34 | 7178449A22579DAB00809DD8 /* DataSourceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7178449922579DAB00809DD8 /* DataSourceViewController.swift */; }; 35 | 7178449D2257B3A700809DD8 /* PaddedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7178449C2257B3A700809DD8 /* PaddedTextField.swift */; }; 36 | 717844A02257F1E300809DD8 /* DataSourcePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7178449F2257F1E300809DD8 /* DataSourcePresenter.swift */; }; 37 | 717844A22257F1F300809DD8 /* DataSourceProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717844A12257F1F300809DD8 /* DataSourceProtocols.swift */; }; 38 | 717844A42257F3A800809DD8 /* DataSourceRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717844A32257F3A800809DD8 /* DataSourceRouter.swift */; }; 39 | 717844A7225B7CEB00809DD8 /* AlgorithmDetailPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717844A6225B7CEB00809DD8 /* AlgorithmDetailPresenterTests.swift */; }; 40 | /* End PBXBuildFile section */ 41 | 42 | /* Begin PBXContainerItemProxy section */ 43 | 716548962253DE8D009C41DD /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 716548792253DE8C009C41DD /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = 716548802253DE8C009C41DD; 48 | remoteInfo = SortingAlgorithms; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | 147EBB4D22A2196A00D19988 /* QuickSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSort.swift; sourceTree = ""; }; 54 | 14E5F58222A46133008537F5 /* QuickSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSortTests.swift; sourceTree = ""; }; 55 | 712E1384225585B100EFBAC9 /* AlgorithmsListProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsListProtocols.swift; sourceTree = ""; }; 56 | 712E13862255874B00EFBAC9 /* AlgorithmsListPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsListPresenter.swift; sourceTree = ""; }; 57 | 712E138A22558AE200EFBAC9 /* UICollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UICollectionViewCell.swift; sourceTree = ""; }; 58 | 712E138C22559D9600EFBAC9 /* AlgorithmsListRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsListRouter.swift; sourceTree = ""; }; 59 | 712E138E2258F09800EFBAC9 /* AlgorithmDetailRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmDetailRouter.swift; sourceTree = ""; }; 60 | 716548812253DE8C009C41DD /* SortingAlgorithms.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SortingAlgorithms.app; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 716548842253DE8C009C41DD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 62 | 716548862253DE8C009C41DD /* AlgorithmsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsListViewController.swift; sourceTree = ""; }; 63 | 7165488B2253DE8D009C41DD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 64 | 7165488E2253DE8D009C41DD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 65 | 716548902253DE8D009C41DD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | 716548952253DE8D009C41DD /* SortingAlgorithmsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SortingAlgorithmsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 716548992253DE8D009C41DD /* BubbleSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleSortTests.swift; sourceTree = ""; }; 68 | 7165489B2253DE8D009C41DD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 716548A92254EB7A009C41DD /* AlgorithmDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmDetailViewController.swift; sourceTree = ""; }; 70 | 716548AB2254EDE7009C41DD /* Algorithm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Algorithm.swift; sourceTree = ""; }; 71 | 716548AD2254EED8009C41DD /* BubbleSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleSort.swift; sourceTree = ""; }; 72 | 716548AF22554791009C41DD /* InsertionSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertionSort.swift; sourceTree = ""; }; 73 | 716548B122554898009C41DD /* AlgorithmDetailPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmDetailPresenter.swift; sourceTree = ""; }; 74 | 716548B3225548B7009C41DD /* AlgorithmDetailProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmDetailProtocol.swift; sourceTree = ""; }; 75 | 716548B522554CEC009C41DD /* AlgorithmsListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsListCell.swift; sourceTree = ""; }; 76 | 716548B722554DDD009C41DD /* AlgorithmDetailCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmDetailCell.swift; sourceTree = ""; }; 77 | 716548B9225551E6009C41DD /* SelectionSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionSort.swift; sourceTree = ""; }; 78 | 716E72E6225AD4D000E436CA /* AlgorithmsListPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsListPresenterTests.swift; sourceTree = ""; }; 79 | 717844912257963400809DD8 /* InsertionSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertionSortTests.swift; sourceTree = ""; }; 80 | 717844932257964000809DD8 /* SelectionSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionSortTests.swift; sourceTree = ""; }; 81 | 7178449922579DAB00809DD8 /* DataSourceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceViewController.swift; sourceTree = ""; }; 82 | 7178449C2257B3A700809DD8 /* PaddedTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaddedTextField.swift; sourceTree = ""; }; 83 | 7178449F2257F1E300809DD8 /* DataSourcePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourcePresenter.swift; sourceTree = ""; }; 84 | 717844A12257F1F300809DD8 /* DataSourceProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceProtocols.swift; sourceTree = ""; }; 85 | 717844A32257F3A800809DD8 /* DataSourceRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSourceRouter.swift; sourceTree = ""; }; 86 | 717844A6225B7CEB00809DD8 /* AlgorithmDetailPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmDetailPresenterTests.swift; sourceTree = ""; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | 7165487E2253DE8C009C41DD /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 716548922253DE8D009C41DD /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | /* End PBXFrameworksBuildPhase section */ 105 | 106 | /* Begin PBXGroup section */ 107 | 712E138822558ACE00EFBAC9 /* Extensions */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 712E138A22558AE200EFBAC9 /* UICollectionViewCell.swift */, 111 | ); 112 | path = Extensions; 113 | sourceTree = ""; 114 | }; 115 | 716548782253DE8C009C41DD = { 116 | isa = PBXGroup; 117 | children = ( 118 | 716548832253DE8C009C41DD /* SortingAlgorithms */, 119 | 716548982253DE8D009C41DD /* SortingAlgorithmsTests */, 120 | 716548822253DE8C009C41DD /* Products */, 121 | ); 122 | sourceTree = ""; 123 | }; 124 | 716548822253DE8C009C41DD /* Products */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 716548812253DE8C009C41DD /* SortingAlgorithms.app */, 128 | 716548952253DE8D009C41DD /* SortingAlgorithmsTests.xctest */, 129 | ); 130 | name = Products; 131 | sourceTree = ""; 132 | }; 133 | 716548832253DE8C009C41DD /* SortingAlgorithms */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 7178449B2257B39100809DD8 /* CustomComponents */, 137 | 712E138822558ACE00EFBAC9 /* Extensions */, 138 | 716548A62253DECC009C41DD /* Scenes */, 139 | 716548A52253DEBA009C41DD /* Algorithms */, 140 | 716548A42253DE95009C41DD /* SupportingFiles */, 141 | ); 142 | path = SortingAlgorithms; 143 | sourceTree = ""; 144 | }; 145 | 716548982253DE8D009C41DD /* SortingAlgorithmsTests */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 716E72E2225AC1F700E436CA /* ModulesTests */, 149 | 71784495225797C400809DD8 /* AlgorithmsTests */, 150 | 7165489B2253DE8D009C41DD /* Info.plist */, 151 | ); 152 | path = SortingAlgorithmsTests; 153 | sourceTree = ""; 154 | }; 155 | 716548A42253DE95009C41DD /* SupportingFiles */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 716548842253DE8C009C41DD /* AppDelegate.swift */, 159 | 7165488B2253DE8D009C41DD /* Assets.xcassets */, 160 | 7165488D2253DE8D009C41DD /* LaunchScreen.storyboard */, 161 | 716548902253DE8D009C41DD /* Info.plist */, 162 | ); 163 | path = SupportingFiles; 164 | sourceTree = ""; 165 | }; 166 | 716548A52253DEBA009C41DD /* Algorithms */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 716548AB2254EDE7009C41DD /* Algorithm.swift */, 170 | 716548AD2254EED8009C41DD /* BubbleSort.swift */, 171 | 716548AF22554791009C41DD /* InsertionSort.swift */, 172 | 716548B9225551E6009C41DD /* SelectionSort.swift */, 173 | 147EBB4D22A2196A00D19988 /* QuickSort.swift */, 174 | ); 175 | path = Algorithms; 176 | sourceTree = ""; 177 | }; 178 | 716548A62253DECC009C41DD /* Scenes */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 7178449E2257D21400809DD8 /* DataSourceInput */, 182 | 716548A82253DF22009C41DD /* AlgorithmDetail */, 183 | 716548A72253DF13009C41DD /* AlgorithmsList */, 184 | ); 185 | path = Scenes; 186 | sourceTree = ""; 187 | }; 188 | 716548A72253DF13009C41DD /* AlgorithmsList */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 716548B522554CEC009C41DD /* AlgorithmsListCell.swift */, 192 | 716548862253DE8C009C41DD /* AlgorithmsListViewController.swift */, 193 | 712E1384225585B100EFBAC9 /* AlgorithmsListProtocols.swift */, 194 | 712E13862255874B00EFBAC9 /* AlgorithmsListPresenter.swift */, 195 | 712E138C22559D9600EFBAC9 /* AlgorithmsListRouter.swift */, 196 | ); 197 | path = AlgorithmsList; 198 | sourceTree = ""; 199 | }; 200 | 716548A82253DF22009C41DD /* AlgorithmDetail */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | 716548B722554DDD009C41DD /* AlgorithmDetailCell.swift */, 204 | 716548A92254EB7A009C41DD /* AlgorithmDetailViewController.swift */, 205 | 716548B122554898009C41DD /* AlgorithmDetailPresenter.swift */, 206 | 716548B3225548B7009C41DD /* AlgorithmDetailProtocol.swift */, 207 | 712E138E2258F09800EFBAC9 /* AlgorithmDetailRouter.swift */, 208 | ); 209 | path = AlgorithmDetail; 210 | sourceTree = ""; 211 | }; 212 | 716E72E2225AC1F700E436CA /* ModulesTests */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | 717844A5225B7CD700809DD8 /* AlgorithmDetail */, 216 | 716E72E3225AD49C00E436CA /* AlgorithmsList */, 217 | ); 218 | path = ModulesTests; 219 | sourceTree = ""; 220 | }; 221 | 716E72E3225AD49C00E436CA /* AlgorithmsList */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | 716E72E6225AD4D000E436CA /* AlgorithmsListPresenterTests.swift */, 225 | ); 226 | path = AlgorithmsList; 227 | sourceTree = ""; 228 | }; 229 | 71784495225797C400809DD8 /* AlgorithmsTests */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | 716548992253DE8D009C41DD /* BubbleSortTests.swift */, 233 | 717844912257963400809DD8 /* InsertionSortTests.swift */, 234 | 717844932257964000809DD8 /* SelectionSortTests.swift */, 235 | 14E5F58222A46133008537F5 /* QuickSortTests.swift */, 236 | ); 237 | path = AlgorithmsTests; 238 | sourceTree = ""; 239 | }; 240 | 7178449B2257B39100809DD8 /* CustomComponents */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | 7178449C2257B3A700809DD8 /* PaddedTextField.swift */, 244 | ); 245 | path = CustomComponents; 246 | sourceTree = ""; 247 | }; 248 | 7178449E2257D21400809DD8 /* DataSourceInput */ = { 249 | isa = PBXGroup; 250 | children = ( 251 | 7178449922579DAB00809DD8 /* DataSourceViewController.swift */, 252 | 7178449F2257F1E300809DD8 /* DataSourcePresenter.swift */, 253 | 717844A12257F1F300809DD8 /* DataSourceProtocols.swift */, 254 | 717844A32257F3A800809DD8 /* DataSourceRouter.swift */, 255 | ); 256 | path = DataSourceInput; 257 | sourceTree = ""; 258 | }; 259 | 717844A5225B7CD700809DD8 /* AlgorithmDetail */ = { 260 | isa = PBXGroup; 261 | children = ( 262 | 717844A6225B7CEB00809DD8 /* AlgorithmDetailPresenterTests.swift */, 263 | ); 264 | path = AlgorithmDetail; 265 | sourceTree = ""; 266 | }; 267 | /* End PBXGroup section */ 268 | 269 | /* Begin PBXNativeTarget section */ 270 | 716548802253DE8C009C41DD /* SortingAlgorithms */ = { 271 | isa = PBXNativeTarget; 272 | buildConfigurationList = 7165489E2253DE8D009C41DD /* Build configuration list for PBXNativeTarget "SortingAlgorithms" */; 273 | buildPhases = ( 274 | 7165487D2253DE8C009C41DD /* Sources */, 275 | 7165487E2253DE8C009C41DD /* Frameworks */, 276 | 7165487F2253DE8C009C41DD /* Resources */, 277 | ); 278 | buildRules = ( 279 | ); 280 | dependencies = ( 281 | ); 282 | name = SortingAlgorithms; 283 | productName = SortingAlgorithms; 284 | productReference = 716548812253DE8C009C41DD /* SortingAlgorithms.app */; 285 | productType = "com.apple.product-type.application"; 286 | }; 287 | 716548942253DE8D009C41DD /* SortingAlgorithmsTests */ = { 288 | isa = PBXNativeTarget; 289 | buildConfigurationList = 716548A12253DE8D009C41DD /* Build configuration list for PBXNativeTarget "SortingAlgorithmsTests" */; 290 | buildPhases = ( 291 | 716548912253DE8D009C41DD /* Sources */, 292 | 716548922253DE8D009C41DD /* Frameworks */, 293 | 716548932253DE8D009C41DD /* Resources */, 294 | ); 295 | buildRules = ( 296 | ); 297 | dependencies = ( 298 | 716548972253DE8D009C41DD /* PBXTargetDependency */, 299 | ); 300 | name = SortingAlgorithmsTests; 301 | productName = SortingAlgorithmsTests; 302 | productReference = 716548952253DE8D009C41DD /* SortingAlgorithmsTests.xctest */; 303 | productType = "com.apple.product-type.bundle.unit-test"; 304 | }; 305 | /* End PBXNativeTarget section */ 306 | 307 | /* Begin PBXProject section */ 308 | 716548792253DE8C009C41DD /* Project object */ = { 309 | isa = PBXProject; 310 | attributes = { 311 | LastSwiftUpdateCheck = 1010; 312 | LastUpgradeCheck = 1010; 313 | ORGANIZATIONNAME = Victor; 314 | TargetAttributes = { 315 | 716548802253DE8C009C41DD = { 316 | CreatedOnToolsVersion = 10.1; 317 | }; 318 | 716548942253DE8D009C41DD = { 319 | CreatedOnToolsVersion = 10.1; 320 | TestTargetID = 716548802253DE8C009C41DD; 321 | }; 322 | }; 323 | }; 324 | buildConfigurationList = 7165487C2253DE8C009C41DD /* Build configuration list for PBXProject "SortingAlgorithms" */; 325 | compatibilityVersion = "Xcode 9.3"; 326 | developmentRegion = en; 327 | hasScannedForEncodings = 0; 328 | knownRegions = ( 329 | en, 330 | Base, 331 | ); 332 | mainGroup = 716548782253DE8C009C41DD; 333 | productRefGroup = 716548822253DE8C009C41DD /* Products */; 334 | projectDirPath = ""; 335 | projectRoot = ""; 336 | targets = ( 337 | 716548802253DE8C009C41DD /* SortingAlgorithms */, 338 | 716548942253DE8D009C41DD /* SortingAlgorithmsTests */, 339 | ); 340 | }; 341 | /* End PBXProject section */ 342 | 343 | /* Begin PBXResourcesBuildPhase section */ 344 | 7165487F2253DE8C009C41DD /* Resources */ = { 345 | isa = PBXResourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | 7165488F2253DE8D009C41DD /* LaunchScreen.storyboard in Resources */, 349 | 7165488C2253DE8D009C41DD /* Assets.xcassets in Resources */, 350 | ); 351 | runOnlyForDeploymentPostprocessing = 0; 352 | }; 353 | 716548932253DE8D009C41DD /* Resources */ = { 354 | isa = PBXResourcesBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | /* End PBXResourcesBuildPhase section */ 361 | 362 | /* Begin PBXSourcesBuildPhase section */ 363 | 7165487D2253DE8C009C41DD /* Sources */ = { 364 | isa = PBXSourcesBuildPhase; 365 | buildActionMask = 2147483647; 366 | files = ( 367 | 716548AA2254EB7A009C41DD /* AlgorithmDetailViewController.swift in Sources */, 368 | 712E1385225585B100EFBAC9 /* AlgorithmsListProtocols.swift in Sources */, 369 | 7178449D2257B3A700809DD8 /* PaddedTextField.swift in Sources */, 370 | 7178449A22579DAB00809DD8 /* DataSourceViewController.swift in Sources */, 371 | 716548872253DE8C009C41DD /* AlgorithmsListViewController.swift in Sources */, 372 | 712E138F2258F09800EFBAC9 /* AlgorithmDetailRouter.swift in Sources */, 373 | 717844A42257F3A800809DD8 /* DataSourceRouter.swift in Sources */, 374 | 717844A22257F1F300809DD8 /* DataSourceProtocols.swift in Sources */, 375 | 717844A02257F1E300809DD8 /* DataSourcePresenter.swift in Sources */, 376 | 716548B222554898009C41DD /* AlgorithmDetailPresenter.swift in Sources */, 377 | 716548B622554CEC009C41DD /* AlgorithmsListCell.swift in Sources */, 378 | 712E138D22559D9600EFBAC9 /* AlgorithmsListRouter.swift in Sources */, 379 | 716548BA225551E6009C41DD /* SelectionSort.swift in Sources */, 380 | 712E13872255874B00EFBAC9 /* AlgorithmsListPresenter.swift in Sources */, 381 | 716548B822554DDD009C41DD /* AlgorithmDetailCell.swift in Sources */, 382 | 147EBB4E22A2196A00D19988 /* QuickSort.swift in Sources */, 383 | 712E138B22558AE200EFBAC9 /* UICollectionViewCell.swift in Sources */, 384 | 716548AE2254EED8009C41DD /* BubbleSort.swift in Sources */, 385 | 716548B4225548B7009C41DD /* AlgorithmDetailProtocol.swift in Sources */, 386 | 716548B022554791009C41DD /* InsertionSort.swift in Sources */, 387 | 716548852253DE8C009C41DD /* AppDelegate.swift in Sources */, 388 | 716548AC2254EDE7009C41DD /* Algorithm.swift in Sources */, 389 | ); 390 | runOnlyForDeploymentPostprocessing = 0; 391 | }; 392 | 716548912253DE8D009C41DD /* Sources */ = { 393 | isa = PBXSourcesBuildPhase; 394 | buildActionMask = 2147483647; 395 | files = ( 396 | 717844A7225B7CEB00809DD8 /* AlgorithmDetailPresenterTests.swift in Sources */, 397 | 717844942257964000809DD8 /* SelectionSortTests.swift in Sources */, 398 | 7165489A2253DE8D009C41DD /* BubbleSortTests.swift in Sources */, 399 | 716E72E7225AD4D000E436CA /* AlgorithmsListPresenterTests.swift in Sources */, 400 | 717844922257963400809DD8 /* InsertionSortTests.swift in Sources */, 401 | 14E5F58322A46133008537F5 /* QuickSortTests.swift in Sources */, 402 | ); 403 | runOnlyForDeploymentPostprocessing = 0; 404 | }; 405 | /* End PBXSourcesBuildPhase section */ 406 | 407 | /* Begin PBXTargetDependency section */ 408 | 716548972253DE8D009C41DD /* PBXTargetDependency */ = { 409 | isa = PBXTargetDependency; 410 | target = 716548802253DE8C009C41DD /* SortingAlgorithms */; 411 | targetProxy = 716548962253DE8D009C41DD /* PBXContainerItemProxy */; 412 | }; 413 | /* End PBXTargetDependency section */ 414 | 415 | /* Begin PBXVariantGroup section */ 416 | 7165488D2253DE8D009C41DD /* LaunchScreen.storyboard */ = { 417 | isa = PBXVariantGroup; 418 | children = ( 419 | 7165488E2253DE8D009C41DD /* Base */, 420 | ); 421 | name = LaunchScreen.storyboard; 422 | sourceTree = ""; 423 | }; 424 | /* End PBXVariantGroup section */ 425 | 426 | /* Begin XCBuildConfiguration section */ 427 | 7165489C2253DE8D009C41DD /* Debug */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ALWAYS_SEARCH_USER_PATHS = NO; 431 | CLANG_ANALYZER_NONNULL = YES; 432 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 433 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 434 | CLANG_CXX_LIBRARY = "libc++"; 435 | CLANG_ENABLE_MODULES = YES; 436 | CLANG_ENABLE_OBJC_ARC = YES; 437 | CLANG_ENABLE_OBJC_WEAK = YES; 438 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 439 | CLANG_WARN_BOOL_CONVERSION = YES; 440 | CLANG_WARN_COMMA = YES; 441 | CLANG_WARN_CONSTANT_CONVERSION = YES; 442 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 443 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 444 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 445 | CLANG_WARN_EMPTY_BODY = YES; 446 | CLANG_WARN_ENUM_CONVERSION = YES; 447 | CLANG_WARN_INFINITE_RECURSION = YES; 448 | CLANG_WARN_INT_CONVERSION = YES; 449 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 450 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 451 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 452 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 453 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 454 | CLANG_WARN_STRICT_PROTOTYPES = YES; 455 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 456 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 457 | CLANG_WARN_UNREACHABLE_CODE = YES; 458 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 459 | CODE_SIGN_IDENTITY = "iPhone Developer"; 460 | COPY_PHASE_STRIP = NO; 461 | CURRENT_PROJECT_VERSION = 1.0.1; 462 | DEBUG_INFORMATION_FORMAT = dwarf; 463 | ENABLE_STRICT_OBJC_MSGSEND = YES; 464 | ENABLE_TESTABILITY = YES; 465 | GCC_C_LANGUAGE_STANDARD = gnu11; 466 | GCC_DYNAMIC_NO_PIC = NO; 467 | GCC_NO_COMMON_BLOCKS = YES; 468 | GCC_OPTIMIZATION_LEVEL = 0; 469 | GCC_PREPROCESSOR_DEFINITIONS = ( 470 | "DEBUG=1", 471 | "$(inherited)", 472 | ); 473 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 474 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 475 | GCC_WARN_UNDECLARED_SELECTOR = YES; 476 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 477 | GCC_WARN_UNUSED_FUNCTION = YES; 478 | GCC_WARN_UNUSED_VARIABLE = YES; 479 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 480 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 481 | MTL_FAST_MATH = YES; 482 | ONLY_ACTIVE_ARCH = YES; 483 | SDKROOT = iphoneos; 484 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 485 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 486 | VERSIONING_SYSTEM = "apple-generic"; 487 | }; 488 | name = Debug; 489 | }; 490 | 7165489D2253DE8D009C41DD /* Release */ = { 491 | isa = XCBuildConfiguration; 492 | buildSettings = { 493 | ALWAYS_SEARCH_USER_PATHS = NO; 494 | CLANG_ANALYZER_NONNULL = YES; 495 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 496 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 497 | CLANG_CXX_LIBRARY = "libc++"; 498 | CLANG_ENABLE_MODULES = YES; 499 | CLANG_ENABLE_OBJC_ARC = YES; 500 | CLANG_ENABLE_OBJC_WEAK = YES; 501 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 502 | CLANG_WARN_BOOL_CONVERSION = YES; 503 | CLANG_WARN_COMMA = YES; 504 | CLANG_WARN_CONSTANT_CONVERSION = YES; 505 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 506 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 507 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 508 | CLANG_WARN_EMPTY_BODY = YES; 509 | CLANG_WARN_ENUM_CONVERSION = YES; 510 | CLANG_WARN_INFINITE_RECURSION = YES; 511 | CLANG_WARN_INT_CONVERSION = YES; 512 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 513 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 514 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 515 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 516 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 517 | CLANG_WARN_STRICT_PROTOTYPES = YES; 518 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 519 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 520 | CLANG_WARN_UNREACHABLE_CODE = YES; 521 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 522 | CODE_SIGN_IDENTITY = "iPhone Developer"; 523 | COPY_PHASE_STRIP = NO; 524 | CURRENT_PROJECT_VERSION = 1.0.1; 525 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 526 | ENABLE_NS_ASSERTIONS = NO; 527 | ENABLE_STRICT_OBJC_MSGSEND = YES; 528 | GCC_C_LANGUAGE_STANDARD = gnu11; 529 | GCC_NO_COMMON_BLOCKS = YES; 530 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 531 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 532 | GCC_WARN_UNDECLARED_SELECTOR = YES; 533 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 534 | GCC_WARN_UNUSED_FUNCTION = YES; 535 | GCC_WARN_UNUSED_VARIABLE = YES; 536 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 537 | MTL_ENABLE_DEBUG_INFO = NO; 538 | MTL_FAST_MATH = YES; 539 | SDKROOT = iphoneos; 540 | SWIFT_COMPILATION_MODE = wholemodule; 541 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 542 | VALIDATE_PRODUCT = YES; 543 | VERSIONING_SYSTEM = "apple-generic"; 544 | }; 545 | name = Release; 546 | }; 547 | 7165489F2253DE8D009C41DD /* Debug */ = { 548 | isa = XCBuildConfiguration; 549 | buildSettings = { 550 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 551 | CODE_SIGN_IDENTITY = "iPhone Developer"; 552 | CODE_SIGN_STYLE = Automatic; 553 | DEVELOPMENT_TEAM = PFBFJV3F25; 554 | INFOPLIST_FILE = SortingAlgorithms/SupportingFiles/Info.plist; 555 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 556 | LD_RUNPATH_SEARCH_PATHS = ( 557 | "$(inherited)", 558 | "@executable_path/Frameworks", 559 | ); 560 | PRODUCT_BUNDLE_IDENTIFIER = victorPanitz.Developer.SortingAlgorithms; 561 | PRODUCT_NAME = "$(TARGET_NAME)"; 562 | PROVISIONING_PROFILE_SPECIFIER = ""; 563 | SWIFT_VERSION = 4.2; 564 | TARGETED_DEVICE_FAMILY = "1,2"; 565 | VERSIONING_SYSTEM = "apple-generic"; 566 | }; 567 | name = Debug; 568 | }; 569 | 716548A02253DE8D009C41DD /* Release */ = { 570 | isa = XCBuildConfiguration; 571 | buildSettings = { 572 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 573 | CODE_SIGN_IDENTITY = "iPhone Developer"; 574 | CODE_SIGN_STYLE = Automatic; 575 | DEVELOPMENT_TEAM = PFBFJV3F25; 576 | INFOPLIST_FILE = SortingAlgorithms/SupportingFiles/Info.plist; 577 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 578 | LD_RUNPATH_SEARCH_PATHS = ( 579 | "$(inherited)", 580 | "@executable_path/Frameworks", 581 | ); 582 | PRODUCT_BUNDLE_IDENTIFIER = victorPanitz.Developer.SortingAlgorithms; 583 | PRODUCT_NAME = "$(TARGET_NAME)"; 584 | PROVISIONING_PROFILE_SPECIFIER = ""; 585 | SWIFT_VERSION = 4.2; 586 | TARGETED_DEVICE_FAMILY = "1,2"; 587 | VERSIONING_SYSTEM = "apple-generic"; 588 | }; 589 | name = Release; 590 | }; 591 | 716548A22253DE8D009C41DD /* Debug */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 595 | BUNDLE_LOADER = "$(TEST_HOST)"; 596 | CODE_SIGN_STYLE = Automatic; 597 | DEVELOPMENT_TEAM = PFBFJV3F25; 598 | INFOPLIST_FILE = SortingAlgorithmsTests/Info.plist; 599 | LD_RUNPATH_SEARCH_PATHS = ( 600 | "$(inherited)", 601 | "@executable_path/Frameworks", 602 | "@loader_path/Frameworks", 603 | ); 604 | PRODUCT_BUNDLE_IDENTIFIER = Victor.SortingAlgorithmsTests; 605 | PRODUCT_NAME = "$(TARGET_NAME)"; 606 | SWIFT_VERSION = 4.2; 607 | TARGETED_DEVICE_FAMILY = "1,2"; 608 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SortingAlgorithms.app/SortingAlgorithms"; 609 | }; 610 | name = Debug; 611 | }; 612 | 716548A32253DE8D009C41DD /* Release */ = { 613 | isa = XCBuildConfiguration; 614 | buildSettings = { 615 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 616 | BUNDLE_LOADER = "$(TEST_HOST)"; 617 | CODE_SIGN_STYLE = Automatic; 618 | DEVELOPMENT_TEAM = PFBFJV3F25; 619 | INFOPLIST_FILE = SortingAlgorithmsTests/Info.plist; 620 | LD_RUNPATH_SEARCH_PATHS = ( 621 | "$(inherited)", 622 | "@executable_path/Frameworks", 623 | "@loader_path/Frameworks", 624 | ); 625 | PRODUCT_BUNDLE_IDENTIFIER = Victor.SortingAlgorithmsTests; 626 | PRODUCT_NAME = "$(TARGET_NAME)"; 627 | SWIFT_VERSION = 4.2; 628 | TARGETED_DEVICE_FAMILY = "1,2"; 629 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SortingAlgorithms.app/SortingAlgorithms"; 630 | }; 631 | name = Release; 632 | }; 633 | /* End XCBuildConfiguration section */ 634 | 635 | /* Begin XCConfigurationList section */ 636 | 7165487C2253DE8C009C41DD /* Build configuration list for PBXProject "SortingAlgorithms" */ = { 637 | isa = XCConfigurationList; 638 | buildConfigurations = ( 639 | 7165489C2253DE8D009C41DD /* Debug */, 640 | 7165489D2253DE8D009C41DD /* Release */, 641 | ); 642 | defaultConfigurationIsVisible = 0; 643 | defaultConfigurationName = Release; 644 | }; 645 | 7165489E2253DE8D009C41DD /* Build configuration list for PBXNativeTarget "SortingAlgorithms" */ = { 646 | isa = XCConfigurationList; 647 | buildConfigurations = ( 648 | 7165489F2253DE8D009C41DD /* Debug */, 649 | 716548A02253DE8D009C41DD /* Release */, 650 | ); 651 | defaultConfigurationIsVisible = 0; 652 | defaultConfigurationName = Release; 653 | }; 654 | 716548A12253DE8D009C41DD /* Build configuration list for PBXNativeTarget "SortingAlgorithmsTests" */ = { 655 | isa = XCConfigurationList; 656 | buildConfigurations = ( 657 | 716548A22253DE8D009C41DD /* Debug */, 658 | 716548A32253DE8D009C41DD /* Release */, 659 | ); 660 | defaultConfigurationIsVisible = 0; 661 | defaultConfigurationName = Release; 662 | }; 663 | /* End XCConfigurationList section */ 664 | }; 665 | rootObject = 716548792253DE8C009C41DD /* Project object */; 666 | } 667 | --------------------------------------------------------------------------------