├── .gitignore ├── LICENSE ├── MovieSearch.xcodeproj └── project.pbxproj ├── Podfile ├── Podfile.lock ├── README.md ├── Ressources ├── App Icon.psd ├── App Icon │ ├── Icon-60.png │ ├── Icon-60@2x.png │ ├── Icon-60@3x.png │ ├── Icon-72.png │ ├── Icon-72@2x.png │ ├── Icon-76.png │ ├── Icon-76@2x.png │ ├── Icon-Small-40.png │ ├── Icon-Small-40@2x.png │ ├── Icon-Small-40@3x.png │ ├── Icon-Small-50.png │ ├── Icon-Small-50@2x.png │ ├── Icon-Small.png │ ├── Icon-Small@2x.png │ ├── Icon-Small@3x.png │ ├── Icon.png │ ├── Icon@2x.png │ └── iTunesArtwork@2x.png ├── Localizable.strings ├── placeholder.png ├── star-gray.png ├── star-gray@2x.png ├── star-gray@3x.png ├── star-gray@4x.png ├── star-yellow.png ├── star-yellow@2x.png ├── star-yellow@3x.png └── star-yellow@4x.png ├── Source ├── Actor.swift ├── ActorCell.swift ├── AlgoliaManager.swift ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.xib │ ├── Main.storyboard │ └── Main_iPad.storyboard ├── ConfigViewController.swift ├── ConfigViewController.xib ├── GenreCell.swift ├── Helpers.swift ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-Small-40@2x.png │ │ ├── Icon-Small-40@3x.png │ │ ├── Icon-Small@2x.png │ │ └── Icon-Small@3x.png │ └── white.imageset │ │ ├── Contents.json │ │ └── white.jpg ├── Info.plist ├── MovieCell.swift ├── MovieRecord.swift ├── MoviesIpadViewController.swift ├── MoviesTableViewController.swift └── RatingSelectorView.swift ├── Tests ├── Info.plist └── MovieSearchTests.swift └── iOS_instant_search.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | Pods/ 21 | *.xcworkspace 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Algolia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MovieSearch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5D44D0031B35F7B3008369AC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D44D0021B35F7B3008369AC /* AppDelegate.swift */; }; 11 | 5D44D0081B35F7B3008369AC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5D44D0061B35F7B3008369AC /* Main.storyboard */; }; 12 | 5D44D00A1B35F7B3008369AC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5D44D0091B35F7B3008369AC /* Images.xcassets */; }; 13 | 5D44D00D1B35F7B3008369AC /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5D44D00B1B35F7B3008369AC /* LaunchScreen.xib */; }; 14 | 5D44D0191B35F7B3008369AC /* MovieSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D44D0181B35F7B3008369AC /* MovieSearchTests.swift */; }; 15 | 5D44D0231B35F87B008369AC /* MoviesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D44D0221B35F87B008369AC /* MoviesTableViewController.swift */; }; 16 | 5D44D0251B3601E8008369AC /* MovieRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D44D0241B3601E8008369AC /* MovieRecord.swift */; }; 17 | 5D9EB6AE1B3C3DC100BA6737 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D9EB6AD1B3C3DC100BA6737 /* Helpers.swift */; }; 18 | 751CCD604AA6A4A8F31209FF /* Pods_MovieSearch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43A7D5DF246F97C734900317 /* Pods_MovieSearch.framework */; }; 19 | BC3A24E61D2AB3D70041870D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BC3A24E51D2AB3D70041870D /* Localizable.strings */; }; 20 | BC3FF4B51CEF0DF6005CCC78 /* AlgoliaManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC3FF4B41CEF0DF6005CCC78 /* AlgoliaManager.swift */; }; 21 | BC3FF4B91CEF1526005CCC78 /* MovieCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC3FF4B81CEF1526005CCC78 /* MovieCell.swift */; }; 22 | BC3FF4BD1CEF4759005CCC78 /* ActorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC3FF4BC1CEF4759005CCC78 /* ActorCell.swift */; }; 23 | BC3FF4BF1CEF4788005CCC78 /* Actor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC3FF4BE1CEF4788005CCC78 /* Actor.swift */; }; 24 | BC58264A1D4B95E80047D27F /* ConfigViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC5826491D4B95E80047D27F /* ConfigViewController.xib */; }; 25 | BC58264D1D4B9A580047D27F /* ConfigViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC58264B1D4B9A580047D27F /* ConfigViewController.swift */; }; 26 | BCA4DA641CEDFCBB00E16ACA /* Main_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BCA4DA621CEDFCBB00E16ACA /* Main_iPad.storyboard */; }; 27 | BCA4DA671CEDFE0300E16ACA /* MoviesIpadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCA4DA651CEDFE0300E16ACA /* MoviesIpadViewController.swift */; }; 28 | BCD754E91CF452EC006A05F1 /* GenreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD754E81CF452EC006A05F1 /* GenreCell.swift */; }; 29 | BCD754ED1CF47E39006A05F1 /* star-yellow@4x.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754EC1CF47E39006A05F1 /* star-yellow@4x.png */; }; 30 | BCD754F21CF47EB6006A05F1 /* star-yellow.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754EF1CF47EB6006A05F1 /* star-yellow.png */; }; 31 | BCD754F31CF47EB6006A05F1 /* star-yellow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754F01CF47EB6006A05F1 /* star-yellow@2x.png */; }; 32 | BCD754F41CF47EB6006A05F1 /* star-yellow@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754F11CF47EB6006A05F1 /* star-yellow@3x.png */; }; 33 | BCD754F91CF4801C006A05F1 /* star-gray.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754F51CF4801C006A05F1 /* star-gray.png */; }; 34 | BCD754FA1CF4801C006A05F1 /* star-gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754F61CF4801C006A05F1 /* star-gray@2x.png */; }; 35 | BCD754FB1CF4801C006A05F1 /* star-gray@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754F71CF4801C006A05F1 /* star-gray@3x.png */; }; 36 | BCD754FC1CF4801C006A05F1 /* star-gray@4x.png in Resources */ = {isa = PBXBuildFile; fileRef = BCD754F81CF4801C006A05F1 /* star-gray@4x.png */; }; 37 | BCD755021CF48168006A05F1 /* RatingSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD755011CF48168006A05F1 /* RatingSelectorView.swift */; }; 38 | BCE9A13A1CFC8A6000BF767D /* placeholder.png in Resources */ = {isa = PBXBuildFile; fileRef = BCE9A1391CFC8A6000BF767D /* placeholder.png */; }; 39 | /* End PBXBuildFile section */ 40 | 41 | /* Begin PBXContainerItemProxy section */ 42 | 5D44D0131B35F7B3008369AC /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 5D44CFF51B35F7B3008369AC /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 5D44CFFC1B35F7B3008369AC; 47 | remoteInfo = MoviesSearch; 48 | }; 49 | /* End PBXContainerItemProxy section */ 50 | 51 | /* Begin PBXFileReference section */ 52 | 31ABE9D8C86A2A514E5B1EDE /* Pods-MovieSearch.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieSearch.release.xcconfig"; path = "Pods/Target Support Files/Pods-MovieSearch/Pods-MovieSearch.release.xcconfig"; sourceTree = ""; }; 53 | 34639E34A7893E96B09FF12B /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 54 | 358F9F4813A5847C2F3EBD96 /* Pods-MoviesSearch.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoviesSearch.release.xcconfig"; path = "Pods/Target Support Files/Pods-MoviesSearch/Pods-MoviesSearch.release.xcconfig"; sourceTree = ""; }; 55 | 43A7D5DF246F97C734900317 /* Pods_MovieSearch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MovieSearch.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 5D44CFFD1B35F7B3008369AC /* MovieSearch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MovieSearch.app; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 5D44D0011B35F7B3008369AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 5D44D0021B35F7B3008369AC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 59 | 5D44D0071B35F7B3008369AC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 60 | 5D44D0091B35F7B3008369AC /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 61 | 5D44D00C1B35F7B3008369AC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 62 | 5D44D0121B35F7B3008369AC /* MovieSearchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MovieSearchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 5D44D0171B35F7B3008369AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | 5D44D0181B35F7B3008369AC /* MovieSearchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieSearchTests.swift; sourceTree = ""; }; 65 | 5D44D0221B35F87B008369AC /* MoviesTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoviesTableViewController.swift; sourceTree = ""; }; 66 | 5D44D0241B3601E8008369AC /* MovieRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MovieRecord.swift; sourceTree = ""; }; 67 | 5D9EB6AD1B3C3DC100BA6737 /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; 68 | 7FFA3B79BEC9E5676A9669C8 /* Pods-MoviesSearch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoviesSearch.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MoviesSearch/Pods-MoviesSearch.debug.xcconfig"; sourceTree = ""; }; 69 | 9BEC1C17860BAEDA209DB025 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 70 | BC3A24E51D2AB3D70041870D /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Localizable.strings; path = Ressources/Localizable.strings; sourceTree = ""; }; 71 | BC3FF4B41CEF0DF6005CCC78 /* AlgoliaManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlgoliaManager.swift; sourceTree = ""; }; 72 | BC3FF4B81CEF1526005CCC78 /* MovieCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MovieCell.swift; sourceTree = ""; }; 73 | BC3FF4BC1CEF4759005CCC78 /* ActorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActorCell.swift; sourceTree = ""; }; 74 | BC3FF4BE1CEF4788005CCC78 /* Actor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actor.swift; sourceTree = ""; }; 75 | BC5826491D4B95E80047D27F /* ConfigViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ConfigViewController.xib; sourceTree = ""; }; 76 | BC58264B1D4B9A580047D27F /* ConfigViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigViewController.swift; sourceTree = ""; }; 77 | BCA4DA631CEDFCBB00E16ACA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPad.storyboard; sourceTree = ""; }; 78 | BCA4DA651CEDFE0300E16ACA /* MoviesIpadViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MoviesIpadViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 79 | BCD754E81CF452EC006A05F1 /* GenreCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenreCell.swift; sourceTree = ""; }; 80 | BCD754EC1CF47E39006A05F1 /* star-yellow@4x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-yellow@4x.png"; path = "Ressources/star-yellow@4x.png"; sourceTree = SOURCE_ROOT; }; 81 | BCD754EF1CF47EB6006A05F1 /* star-yellow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-yellow.png"; path = "Ressources/star-yellow.png"; sourceTree = ""; }; 82 | BCD754F01CF47EB6006A05F1 /* star-yellow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-yellow@2x.png"; path = "Ressources/star-yellow@2x.png"; sourceTree = ""; }; 83 | BCD754F11CF47EB6006A05F1 /* star-yellow@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-yellow@3x.png"; path = "Ressources/star-yellow@3x.png"; sourceTree = ""; }; 84 | BCD754F51CF4801C006A05F1 /* star-gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-gray.png"; path = "Ressources/star-gray.png"; sourceTree = ""; }; 85 | BCD754F61CF4801C006A05F1 /* star-gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-gray@2x.png"; path = "Ressources/star-gray@2x.png"; sourceTree = ""; }; 86 | BCD754F71CF4801C006A05F1 /* star-gray@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-gray@3x.png"; path = "Ressources/star-gray@3x.png"; sourceTree = ""; }; 87 | BCD754F81CF4801C006A05F1 /* star-gray@4x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "star-gray@4x.png"; path = "Ressources/star-gray@4x.png"; sourceTree = ""; }; 88 | BCD755011CF48168006A05F1 /* RatingSelectorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RatingSelectorView.swift; sourceTree = ""; }; 89 | BCE9A1391CFC8A6000BF767D /* placeholder.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = placeholder.png; path = Ressources/placeholder.png; sourceTree = ""; }; 90 | D2954C98D66239E67B3B3D52 /* Pods-MovieSearch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MovieSearch.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MovieSearch/Pods-MovieSearch.debug.xcconfig"; sourceTree = ""; }; 91 | /* End PBXFileReference section */ 92 | 93 | /* Begin PBXFrameworksBuildPhase section */ 94 | 5D44CFFA1B35F7B3008369AC /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | 751CCD604AA6A4A8F31209FF /* Pods_MovieSearch.framework in Frameworks */, 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | 5D44D00F1B35F7B3008369AC /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | /* End PBXFrameworksBuildPhase section */ 110 | 111 | /* Begin PBXGroup section */ 112 | 5D44CFF41B35F7B3008369AC = { 113 | isa = PBXGroup; 114 | children = ( 115 | 5D44CFFF1B35F7B3008369AC /* Source */, 116 | BCD754EE1CF47E40006A05F1 /* Resources */, 117 | 5D44D0151B35F7B3008369AC /* Tests */, 118 | 5D44CFFE1B35F7B3008369AC /* Products */, 119 | 6120C880B8039A7CEF4D6A02 /* Pods */, 120 | C34AD11619D3010C523C954D /* Frameworks */, 121 | ); 122 | sourceTree = ""; 123 | }; 124 | 5D44CFFE1B35F7B3008369AC /* Products */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 5D44CFFD1B35F7B3008369AC /* MovieSearch.app */, 128 | 5D44D0121B35F7B3008369AC /* MovieSearchTests.xctest */, 129 | ); 130 | name = Products; 131 | sourceTree = ""; 132 | }; 133 | 5D44CFFF1B35F7B3008369AC /* Source */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 5D44D0021B35F7B3008369AC /* AppDelegate.swift */, 137 | 5D44D0221B35F87B008369AC /* MoviesTableViewController.swift */, 138 | 5D44D0241B3601E8008369AC /* MovieRecord.swift */, 139 | 5D9EB6AD1B3C3DC100BA6737 /* Helpers.swift */, 140 | 5D44D0061B35F7B3008369AC /* Main.storyboard */, 141 | 5D44D0091B35F7B3008369AC /* Images.xcassets */, 142 | 5D44D00B1B35F7B3008369AC /* LaunchScreen.xib */, 143 | 5D44D0001B35F7B3008369AC /* Supporting Files */, 144 | BCA4DA621CEDFCBB00E16ACA /* Main_iPad.storyboard */, 145 | BCA4DA651CEDFE0300E16ACA /* MoviesIpadViewController.swift */, 146 | BC3FF4B41CEF0DF6005CCC78 /* AlgoliaManager.swift */, 147 | BC3FF4B81CEF1526005CCC78 /* MovieCell.swift */, 148 | BC3FF4BC1CEF4759005CCC78 /* ActorCell.swift */, 149 | BC3FF4BE1CEF4788005CCC78 /* Actor.swift */, 150 | BCD754E81CF452EC006A05F1 /* GenreCell.swift */, 151 | BCD755011CF48168006A05F1 /* RatingSelectorView.swift */, 152 | BC5826491D4B95E80047D27F /* ConfigViewController.xib */, 153 | BC58264B1D4B9A580047D27F /* ConfigViewController.swift */, 154 | ); 155 | path = Source; 156 | sourceTree = ""; 157 | }; 158 | 5D44D0001B35F7B3008369AC /* Supporting Files */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 5D44D0011B35F7B3008369AC /* Info.plist */, 162 | ); 163 | name = "Supporting Files"; 164 | sourceTree = ""; 165 | }; 166 | 5D44D0151B35F7B3008369AC /* Tests */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 5D44D0181B35F7B3008369AC /* MovieSearchTests.swift */, 170 | 5D44D0161B35F7B3008369AC /* Supporting Files */, 171 | ); 172 | path = Tests; 173 | sourceTree = ""; 174 | }; 175 | 5D44D0161B35F7B3008369AC /* Supporting Files */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 5D44D0171B35F7B3008369AC /* Info.plist */, 179 | ); 180 | name = "Supporting Files"; 181 | sourceTree = ""; 182 | }; 183 | 6120C880B8039A7CEF4D6A02 /* Pods */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 9BEC1C17860BAEDA209DB025 /* Pods.debug.xcconfig */, 187 | 34639E34A7893E96B09FF12B /* Pods.release.xcconfig */, 188 | 7FFA3B79BEC9E5676A9669C8 /* Pods-MoviesSearch.debug.xcconfig */, 189 | 358F9F4813A5847C2F3EBD96 /* Pods-MoviesSearch.release.xcconfig */, 190 | D2954C98D66239E67B3B3D52 /* Pods-MovieSearch.debug.xcconfig */, 191 | 31ABE9D8C86A2A514E5B1EDE /* Pods-MovieSearch.release.xcconfig */, 192 | ); 193 | name = Pods; 194 | sourceTree = ""; 195 | }; 196 | BCD754EE1CF47E40006A05F1 /* Resources */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | BCE9A1391CFC8A6000BF767D /* placeholder.png */, 200 | BCD754F51CF4801C006A05F1 /* star-gray.png */, 201 | BCD754F61CF4801C006A05F1 /* star-gray@2x.png */, 202 | BCD754F71CF4801C006A05F1 /* star-gray@3x.png */, 203 | BCD754F81CF4801C006A05F1 /* star-gray@4x.png */, 204 | BCD754EF1CF47EB6006A05F1 /* star-yellow.png */, 205 | BCD754F01CF47EB6006A05F1 /* star-yellow@2x.png */, 206 | BCD754F11CF47EB6006A05F1 /* star-yellow@3x.png */, 207 | BCD754EC1CF47E39006A05F1 /* star-yellow@4x.png */, 208 | BC3A24E51D2AB3D70041870D /* Localizable.strings */, 209 | ); 210 | name = Resources; 211 | sourceTree = ""; 212 | }; 213 | C34AD11619D3010C523C954D /* Frameworks */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 43A7D5DF246F97C734900317 /* Pods_MovieSearch.framework */, 217 | ); 218 | name = Frameworks; 219 | sourceTree = ""; 220 | }; 221 | /* End PBXGroup section */ 222 | 223 | /* Begin PBXNativeTarget section */ 224 | 5D44CFFC1B35F7B3008369AC /* MovieSearch */ = { 225 | isa = PBXNativeTarget; 226 | buildConfigurationList = 5D44D01C1B35F7B3008369AC /* Build configuration list for PBXNativeTarget "MovieSearch" */; 227 | buildPhases = ( 228 | 073B008BF094C3613460DB4D /* [CP] Check Pods Manifest.lock */, 229 | 5D44CFF91B35F7B3008369AC /* Sources */, 230 | 5D44CFFA1B35F7B3008369AC /* Frameworks */, 231 | 5D44CFFB1B35F7B3008369AC /* Resources */, 232 | 27819121FF8995793C4CFEA3 /* [CP] Embed Pods Frameworks */, 233 | 1F35BD3D3B964F386A6FCA62 /* [CP] Copy Pods Resources */, 234 | ); 235 | buildRules = ( 236 | ); 237 | dependencies = ( 238 | ); 239 | name = MovieSearch; 240 | productName = MoviesSearch; 241 | productReference = 5D44CFFD1B35F7B3008369AC /* MovieSearch.app */; 242 | productType = "com.apple.product-type.application"; 243 | }; 244 | 5D44D0111B35F7B3008369AC /* MovieSearchTests */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = 5D44D01F1B35F7B3008369AC /* Build configuration list for PBXNativeTarget "MovieSearchTests" */; 247 | buildPhases = ( 248 | 5D44D00E1B35F7B3008369AC /* Sources */, 249 | 5D44D00F1B35F7B3008369AC /* Frameworks */, 250 | 5D44D0101B35F7B3008369AC /* Resources */, 251 | ); 252 | buildRules = ( 253 | ); 254 | dependencies = ( 255 | 5D44D0141B35F7B3008369AC /* PBXTargetDependency */, 256 | ); 257 | name = MovieSearchTests; 258 | productName = MoviesSearchTests; 259 | productReference = 5D44D0121B35F7B3008369AC /* MovieSearchTests.xctest */; 260 | productType = "com.apple.product-type.bundle.unit-test"; 261 | }; 262 | /* End PBXNativeTarget section */ 263 | 264 | /* Begin PBXProject section */ 265 | 5D44CFF51B35F7B3008369AC /* Project object */ = { 266 | isa = PBXProject; 267 | attributes = { 268 | LastSwiftMigration = 0720; 269 | LastSwiftUpdateCheck = 0720; 270 | LastUpgradeCheck = 0800; 271 | ORGANIZATIONNAME = "Thibault Deutsch"; 272 | TargetAttributes = { 273 | 5D44CFFC1B35F7B3008369AC = { 274 | CreatedOnToolsVersion = 6.3.2; 275 | }; 276 | 5D44D0111B35F7B3008369AC = { 277 | CreatedOnToolsVersion = 6.3.2; 278 | TestTargetID = 5D44CFFC1B35F7B3008369AC; 279 | }; 280 | }; 281 | }; 282 | buildConfigurationList = 5D44CFF81B35F7B3008369AC /* Build configuration list for PBXProject "MovieSearch" */; 283 | compatibilityVersion = "Xcode 3.2"; 284 | developmentRegion = English; 285 | hasScannedForEncodings = 0; 286 | knownRegions = ( 287 | en, 288 | Base, 289 | ); 290 | mainGroup = 5D44CFF41B35F7B3008369AC; 291 | productRefGroup = 5D44CFFE1B35F7B3008369AC /* Products */; 292 | projectDirPath = ""; 293 | projectRoot = ""; 294 | targets = ( 295 | 5D44CFFC1B35F7B3008369AC /* MovieSearch */, 296 | 5D44D0111B35F7B3008369AC /* MovieSearchTests */, 297 | ); 298 | }; 299 | /* End PBXProject section */ 300 | 301 | /* Begin PBXResourcesBuildPhase section */ 302 | 5D44CFFB1B35F7B3008369AC /* Resources */ = { 303 | isa = PBXResourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | BCD754F31CF47EB6006A05F1 /* star-yellow@2x.png in Resources */, 307 | BCD754FA1CF4801C006A05F1 /* star-gray@2x.png in Resources */, 308 | BCD754ED1CF47E39006A05F1 /* star-yellow@4x.png in Resources */, 309 | BC3A24E61D2AB3D70041870D /* Localizable.strings in Resources */, 310 | BCE9A13A1CFC8A6000BF767D /* placeholder.png in Resources */, 311 | BCD754FB1CF4801C006A05F1 /* star-gray@3x.png in Resources */, 312 | BCD754F91CF4801C006A05F1 /* star-gray.png in Resources */, 313 | BCD754FC1CF4801C006A05F1 /* star-gray@4x.png in Resources */, 314 | 5D44D0081B35F7B3008369AC /* Main.storyboard in Resources */, 315 | BCD754F41CF47EB6006A05F1 /* star-yellow@3x.png in Resources */, 316 | BCA4DA641CEDFCBB00E16ACA /* Main_iPad.storyboard in Resources */, 317 | BCD754F21CF47EB6006A05F1 /* star-yellow.png in Resources */, 318 | 5D44D00D1B35F7B3008369AC /* LaunchScreen.xib in Resources */, 319 | BC58264A1D4B95E80047D27F /* ConfigViewController.xib in Resources */, 320 | 5D44D00A1B35F7B3008369AC /* Images.xcassets in Resources */, 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | 5D44D0101B35F7B3008369AC /* Resources */ = { 325 | isa = PBXResourcesBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | /* End PBXResourcesBuildPhase section */ 332 | 333 | /* Begin PBXShellScriptBuildPhase section */ 334 | 073B008BF094C3613460DB4D /* [CP] Check Pods Manifest.lock */ = { 335 | isa = PBXShellScriptBuildPhase; 336 | buildActionMask = 2147483647; 337 | files = ( 338 | ); 339 | inputPaths = ( 340 | ); 341 | name = "[CP] Check Pods Manifest.lock"; 342 | outputPaths = ( 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | shellPath = /bin/sh; 346 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 347 | showEnvVarsInLog = 0; 348 | }; 349 | 1F35BD3D3B964F386A6FCA62 /* [CP] Copy Pods Resources */ = { 350 | isa = PBXShellScriptBuildPhase; 351 | buildActionMask = 2147483647; 352 | files = ( 353 | ); 354 | inputPaths = ( 355 | ); 356 | name = "[CP] Copy Pods Resources"; 357 | outputPaths = ( 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | shellPath = /bin/sh; 361 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MovieSearch/Pods-MovieSearch-resources.sh\"\n"; 362 | showEnvVarsInLog = 0; 363 | }; 364 | 27819121FF8995793C4CFEA3 /* [CP] Embed Pods Frameworks */ = { 365 | isa = PBXShellScriptBuildPhase; 366 | buildActionMask = 2147483647; 367 | files = ( 368 | ); 369 | inputPaths = ( 370 | ); 371 | name = "[CP] Embed Pods Frameworks"; 372 | outputPaths = ( 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | shellPath = /bin/sh; 376 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MovieSearch/Pods-MovieSearch-frameworks.sh\"\n"; 377 | showEnvVarsInLog = 0; 378 | }; 379 | /* End PBXShellScriptBuildPhase section */ 380 | 381 | /* Begin PBXSourcesBuildPhase section */ 382 | 5D44CFF91B35F7B3008369AC /* Sources */ = { 383 | isa = PBXSourcesBuildPhase; 384 | buildActionMask = 2147483647; 385 | files = ( 386 | 5D44D0231B35F87B008369AC /* MoviesTableViewController.swift in Sources */, 387 | BCA4DA671CEDFE0300E16ACA /* MoviesIpadViewController.swift in Sources */, 388 | BC58264D1D4B9A580047D27F /* ConfigViewController.swift in Sources */, 389 | BC3FF4BD1CEF4759005CCC78 /* ActorCell.swift in Sources */, 390 | BC3FF4B91CEF1526005CCC78 /* MovieCell.swift in Sources */, 391 | 5D44D0251B3601E8008369AC /* MovieRecord.swift in Sources */, 392 | 5D44D0031B35F7B3008369AC /* AppDelegate.swift in Sources */, 393 | 5D9EB6AE1B3C3DC100BA6737 /* Helpers.swift in Sources */, 394 | BC3FF4B51CEF0DF6005CCC78 /* AlgoliaManager.swift in Sources */, 395 | BCD754E91CF452EC006A05F1 /* GenreCell.swift in Sources */, 396 | BC3FF4BF1CEF4788005CCC78 /* Actor.swift in Sources */, 397 | BCD755021CF48168006A05F1 /* RatingSelectorView.swift in Sources */, 398 | ); 399 | runOnlyForDeploymentPostprocessing = 0; 400 | }; 401 | 5D44D00E1B35F7B3008369AC /* Sources */ = { 402 | isa = PBXSourcesBuildPhase; 403 | buildActionMask = 2147483647; 404 | files = ( 405 | 5D44D0191B35F7B3008369AC /* MovieSearchTests.swift in Sources */, 406 | ); 407 | runOnlyForDeploymentPostprocessing = 0; 408 | }; 409 | /* End PBXSourcesBuildPhase section */ 410 | 411 | /* Begin PBXTargetDependency section */ 412 | 5D44D0141B35F7B3008369AC /* PBXTargetDependency */ = { 413 | isa = PBXTargetDependency; 414 | target = 5D44CFFC1B35F7B3008369AC /* MovieSearch */; 415 | targetProxy = 5D44D0131B35F7B3008369AC /* PBXContainerItemProxy */; 416 | }; 417 | /* End PBXTargetDependency section */ 418 | 419 | /* Begin PBXVariantGroup section */ 420 | 5D44D0061B35F7B3008369AC /* Main.storyboard */ = { 421 | isa = PBXVariantGroup; 422 | children = ( 423 | 5D44D0071B35F7B3008369AC /* Base */, 424 | ); 425 | name = Main.storyboard; 426 | sourceTree = ""; 427 | }; 428 | 5D44D00B1B35F7B3008369AC /* LaunchScreen.xib */ = { 429 | isa = PBXVariantGroup; 430 | children = ( 431 | 5D44D00C1B35F7B3008369AC /* Base */, 432 | ); 433 | name = LaunchScreen.xib; 434 | sourceTree = ""; 435 | }; 436 | BCA4DA621CEDFCBB00E16ACA /* Main_iPad.storyboard */ = { 437 | isa = PBXVariantGroup; 438 | children = ( 439 | BCA4DA631CEDFCBB00E16ACA /* Base */, 440 | ); 441 | name = Main_iPad.storyboard; 442 | sourceTree = ""; 443 | }; 444 | /* End PBXVariantGroup section */ 445 | 446 | /* Begin XCBuildConfiguration section */ 447 | 5D44D01A1B35F7B3008369AC /* Debug */ = { 448 | isa = XCBuildConfiguration; 449 | buildSettings = { 450 | ALWAYS_SEARCH_USER_PATHS = NO; 451 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 452 | CLANG_CXX_LIBRARY = "libc++"; 453 | CLANG_ENABLE_MODULES = YES; 454 | CLANG_ENABLE_OBJC_ARC = YES; 455 | CLANG_WARN_BOOL_CONVERSION = YES; 456 | CLANG_WARN_CONSTANT_CONVERSION = YES; 457 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 458 | CLANG_WARN_EMPTY_BODY = YES; 459 | CLANG_WARN_ENUM_CONVERSION = YES; 460 | CLANG_WARN_INFINITE_RECURSION = YES; 461 | CLANG_WARN_INT_CONVERSION = YES; 462 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 463 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 464 | CLANG_WARN_UNREACHABLE_CODE = YES; 465 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 466 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 467 | COPY_PHASE_STRIP = NO; 468 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 469 | ENABLE_BITCODE = NO; 470 | ENABLE_STRICT_OBJC_MSGSEND = YES; 471 | ENABLE_TESTABILITY = YES; 472 | GCC_C_LANGUAGE_STANDARD = gnu99; 473 | GCC_DYNAMIC_NO_PIC = NO; 474 | GCC_NO_COMMON_BLOCKS = YES; 475 | GCC_OPTIMIZATION_LEVEL = 0; 476 | GCC_PREPROCESSOR_DEFINITIONS = ( 477 | "DEBUG=1", 478 | "$(inherited)", 479 | ); 480 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 481 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 482 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 483 | GCC_WARN_UNDECLARED_SELECTOR = YES; 484 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 485 | GCC_WARN_UNUSED_FUNCTION = YES; 486 | GCC_WARN_UNUSED_VARIABLE = YES; 487 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 488 | MTL_ENABLE_DEBUG_INFO = YES; 489 | ONLY_ACTIVE_ARCH = YES; 490 | OTHER_SWIFT_FLAGS = "-DDEBUG"; 491 | SDKROOT = iphoneos; 492 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 493 | SWIFT_VERSION = 3.0; 494 | }; 495 | name = Debug; 496 | }; 497 | 5D44D01B1B35F7B3008369AC /* Release */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | ALWAYS_SEARCH_USER_PATHS = NO; 501 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 502 | CLANG_CXX_LIBRARY = "libc++"; 503 | CLANG_ENABLE_MODULES = YES; 504 | CLANG_ENABLE_OBJC_ARC = YES; 505 | CLANG_WARN_BOOL_CONVERSION = YES; 506 | CLANG_WARN_CONSTANT_CONVERSION = YES; 507 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_OBJC_ROOT_CLASS = YES_ERROR; 513 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 514 | CLANG_WARN_UNREACHABLE_CODE = YES; 515 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 516 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 517 | COPY_PHASE_STRIP = NO; 518 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 519 | ENABLE_BITCODE = NO; 520 | ENABLE_NS_ASSERTIONS = NO; 521 | ENABLE_STRICT_OBJC_MSGSEND = YES; 522 | GCC_C_LANGUAGE_STANDARD = gnu99; 523 | GCC_NO_COMMON_BLOCKS = YES; 524 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 525 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 526 | GCC_WARN_UNDECLARED_SELECTOR = YES; 527 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 528 | GCC_WARN_UNUSED_FUNCTION = YES; 529 | GCC_WARN_UNUSED_VARIABLE = YES; 530 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 531 | MTL_ENABLE_DEBUG_INFO = NO; 532 | SDKROOT = iphoneos; 533 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 534 | SWIFT_VERSION = 3.0; 535 | VALIDATE_PRODUCT = YES; 536 | }; 537 | name = Release; 538 | }; 539 | 5D44D01D1B35F7B3008369AC /* Debug */ = { 540 | isa = XCBuildConfiguration; 541 | baseConfigurationReference = D2954C98D66239E67B3B3D52 /* Pods-MovieSearch.debug.xcconfig */; 542 | buildSettings = { 543 | ALGOLIA_API_KEY = d0a23086ed4be550f70be98c0acf7d74; 544 | ALGOLIA_OFFLINE_SDK_LICENSE_KEY = "AkUCAQH/xpXDBf/y3rwFlwcYQWxnb2xpYSBEZXZlbG9wbWVudCBUZWFtHGNvbS5hbGdvbGlhLmRlbW8uTW92aWVTZWFyY2gwLQIUbyf1iq0UYpn71/FU817dT6Jrna8CFQDN+6S7XfBA20r7/rn8A1oqBc2fZw=="; 545 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 546 | CODE_SIGN_IDENTITY = "iPhone Developer"; 547 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 548 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 549 | PRODUCT_BUNDLE_IDENTIFIER = "com.algolia.demo.$(PRODUCT_NAME:rfc1034identifier)"; 550 | PRODUCT_NAME = "$(TARGET_NAME)"; 551 | TARGETED_DEVICE_FAMILY = "1,2"; 552 | }; 553 | name = Debug; 554 | }; 555 | 5D44D01E1B35F7B3008369AC /* Release */ = { 556 | isa = XCBuildConfiguration; 557 | baseConfigurationReference = 31ABE9D8C86A2A514E5B1EDE /* Pods-MovieSearch.release.xcconfig */; 558 | buildSettings = { 559 | ALGOLIA_API_KEY = d0a23086ed4be550f70be98c0acf7d74; 560 | ALGOLIA_OFFLINE_SDK_LICENSE_KEY = "AkUCAQH/xpXDBf/y3rwFlwcYQWxnb2xpYSBEZXZlbG9wbWVudCBUZWFtHGNvbS5hbGdvbGlhLmRlbW8uTW92aWVTZWFyY2gwLQIUbyf1iq0UYpn71/FU817dT6Jrna8CFQDN+6S7XfBA20r7/rn8A1oqBc2fZw=="; 561 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 562 | CODE_SIGN_IDENTITY = "iPhone Developer"; 563 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 564 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 565 | PRODUCT_BUNDLE_IDENTIFIER = "com.algolia.demo.$(PRODUCT_NAME:rfc1034identifier)"; 566 | PRODUCT_NAME = "$(TARGET_NAME)"; 567 | TARGETED_DEVICE_FAMILY = "1,2"; 568 | }; 569 | name = Release; 570 | }; 571 | 5D44D0201B35F7B3008369AC /* Debug */ = { 572 | isa = XCBuildConfiguration; 573 | buildSettings = { 574 | BUNDLE_LOADER = "$(TEST_HOST)"; 575 | FRAMEWORK_SEARCH_PATHS = ( 576 | "$(SDKROOT)/Developer/Library/Frameworks", 577 | "$(inherited)", 578 | ); 579 | GCC_PREPROCESSOR_DEFINITIONS = ( 580 | "DEBUG=1", 581 | "$(inherited)", 582 | ); 583 | INFOPLIST_FILE = Tests/Info.plist; 584 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 585 | PRODUCT_BUNDLE_IDENTIFIER = "com.algolia.$(PRODUCT_NAME:rfc1034identifier)"; 586 | PRODUCT_NAME = "$(TARGET_NAME)"; 587 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).app/$(PRODUCT_NAME)"; 588 | }; 589 | name = Debug; 590 | }; 591 | 5D44D0211B35F7B3008369AC /* Release */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | BUNDLE_LOADER = "$(TEST_HOST)"; 595 | FRAMEWORK_SEARCH_PATHS = ( 596 | "$(SDKROOT)/Developer/Library/Frameworks", 597 | "$(inherited)", 598 | ); 599 | INFOPLIST_FILE = Tests/Info.plist; 600 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 601 | PRODUCT_BUNDLE_IDENTIFIER = "com.algolia.$(PRODUCT_NAME:rfc1034identifier)"; 602 | PRODUCT_NAME = "$(TARGET_NAME)"; 603 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).app/$(PRODUCT_NAME)"; 604 | }; 605 | name = Release; 606 | }; 607 | /* End XCBuildConfiguration section */ 608 | 609 | /* Begin XCConfigurationList section */ 610 | 5D44CFF81B35F7B3008369AC /* Build configuration list for PBXProject "MovieSearch" */ = { 611 | isa = XCConfigurationList; 612 | buildConfigurations = ( 613 | 5D44D01A1B35F7B3008369AC /* Debug */, 614 | 5D44D01B1B35F7B3008369AC /* Release */, 615 | ); 616 | defaultConfigurationIsVisible = 0; 617 | defaultConfigurationName = Release; 618 | }; 619 | 5D44D01C1B35F7B3008369AC /* Build configuration list for PBXNativeTarget "MovieSearch" */ = { 620 | isa = XCConfigurationList; 621 | buildConfigurations = ( 622 | 5D44D01D1B35F7B3008369AC /* Debug */, 623 | 5D44D01E1B35F7B3008369AC /* Release */, 624 | ); 625 | defaultConfigurationIsVisible = 0; 626 | defaultConfigurationName = Release; 627 | }; 628 | 5D44D01F1B35F7B3008369AC /* Build configuration list for PBXNativeTarget "MovieSearchTests" */ = { 629 | isa = XCConfigurationList; 630 | buildConfigurations = ( 631 | 5D44D0201B35F7B3008369AC /* Debug */, 632 | 5D44D0211B35F7B3008369AC /* Release */, 633 | ); 634 | defaultConfigurationIsVisible = 0; 635 | defaultConfigurationName = Release; 636 | }; 637 | /* End XCConfigurationList section */ 638 | }; 639 | rootObject = 5D44CFF51B35F7B3008369AC /* Project object */; 640 | } 641 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target "MovieSearch" do 4 | pod 'InstantSearch-Core-Swift', '~> 1.0' 5 | pod 'AFNetworking', '~> 3.0' 6 | pod 'Reachability', '~> 3.2' 7 | pod 'TTRangeSlider', :git => 'https://github.com/TomThorpe/TTRangeSlider', :branch => 'master' 8 | end 9 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AFNetworking (3.1.0): 3 | - AFNetworking/NSURLSession (= 3.1.0) 4 | - AFNetworking/Reachability (= 3.1.0) 5 | - AFNetworking/Security (= 3.1.0) 6 | - AFNetworking/Serialization (= 3.1.0) 7 | - AFNetworking/UIKit (= 3.1.0) 8 | - AFNetworking/NSURLSession (3.1.0): 9 | - AFNetworking/Reachability 10 | - AFNetworking/Security 11 | - AFNetworking/Serialization 12 | - AFNetworking/Reachability (3.1.0) 13 | - AFNetworking/Security (3.1.0) 14 | - AFNetworking/Serialization (3.1.0) 15 | - AFNetworking/UIKit (3.1.0): 16 | - AFNetworking/NSURLSession 17 | - AlgoliaSearch-Client-Swift (4.5) 18 | - InstantSearch-Core-Swift (1.0): 19 | - AlgoliaSearch-Client-Swift (~> 4.0) 20 | - Reachability (3.2) 21 | - TTRangeSlider (1.0.5) 22 | 23 | DEPENDENCIES: 24 | - AFNetworking (~> 3.0) 25 | - InstantSearch-Core-Swift (~> 1.0) 26 | - Reachability (~> 3.2) 27 | - TTRangeSlider (from `https://github.com/TomThorpe/TTRangeSlider`, branch `master`) 28 | 29 | EXTERNAL SOURCES: 30 | TTRangeSlider: 31 | :branch: master 32 | :git: https://github.com/TomThorpe/TTRangeSlider 33 | 34 | CHECKOUT OPTIONS: 35 | TTRangeSlider: 36 | :commit: 00752f8ca0b65f93fe4ab007b40953c0ab184313 37 | :git: https://github.com/TomThorpe/TTRangeSlider 38 | 39 | SPEC CHECKSUMS: 40 | AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67 41 | AlgoliaSearch-Client-Swift: c7662215a44392430635a922234c1c04e64ee17b 42 | InstantSearch-Core-Swift: 7fcdf313c2d8f2fea9edc975319a7b4626e50e53 43 | Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 44 | TTRangeSlider: 2f2ce4a33b32bb323c6575b9f5161c4664459c58 45 | 46 | PODFILE CHECKSUM: 381515db7583d99667dea5637a2fffa91505c830 47 | 48 | COCOAPODS: 1.2.0.beta.1 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated, please use our [new repo](https://github.com/algolia/instantsearch-ios-examples) 2 | 3 | ## iOS instant search demo 4 | 5 | This is a sample project implementing an instant-search view with [Algolia](https://www.algolia.com/). Algolia is a Search API that provides hosted full-text, numerical and faceted search. 6 | 7 | ## Features 8 | 9 | * Full Swift using the [AlgoliaSearch Swift API client](https://github.com/algolia/algoliasearch-client-swift) 10 | * Displaying results as you type 11 | * Match highlighting 12 | * Infinite scroll 13 | 14 | ## Setup 15 | 16 | * Clone the repository 17 | * `pod install` 18 | * Open the Xcode Workspace 19 | * Build & Run! 20 | 21 | ## Tutorial 22 | 23 | **Follow this [step by step tutorial](https://www.algolia.com/doc/tutorials/ios-instant-search) (on Algolia.com) to learn how this implementation works** and how it has been built using the [Algolia's Swift API Client](https://github.com/algolia/algoliasearch-client-swift). 24 | 25 | ## See it in action 26 | 27 | ![iOS-instant-search.gif](iOS_instant_search.gif) 28 | -------------------------------------------------------------------------------- /Ressources/App Icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon.psd -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-60.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-60@2x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-60@3x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-72.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-72@2x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-76.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-76@2x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small-40.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small-50.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small-50@2x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small@2x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon-Small@3x.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon.png -------------------------------------------------------------------------------- /Ressources/App Icon/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/Icon@2x.png -------------------------------------------------------------------------------- /Ressources/App Icon/iTunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/App Icon/iTunesArtwork@2x.png -------------------------------------------------------------------------------- /Ressources/Localizable.strings: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | "error_search" = "Search failed. Check your Internet settings."; 25 | "movie_count_placeholder" = "MOVIES"; 26 | "search_bar_placeholder" = "Search for movies or actors…"; 27 | -------------------------------------------------------------------------------- /Ressources/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/placeholder.png -------------------------------------------------------------------------------- /Ressources/star-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-gray.png -------------------------------------------------------------------------------- /Ressources/star-gray@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-gray@2x.png -------------------------------------------------------------------------------- /Ressources/star-gray@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-gray@3x.png -------------------------------------------------------------------------------- /Ressources/star-gray@4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-gray@4x.png -------------------------------------------------------------------------------- /Ressources/star-yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-yellow.png -------------------------------------------------------------------------------- /Ressources/star-yellow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-yellow@2x.png -------------------------------------------------------------------------------- /Ressources/star-yellow@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-yellow@3x.png -------------------------------------------------------------------------------- /Ressources/star-yellow@4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Ressources/star-yellow@4x.png -------------------------------------------------------------------------------- /Source/Actor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import AlgoliaSearch 25 | import InstantSearchCore 26 | import Foundation 27 | 28 | 29 | struct Actor { 30 | private let json: JSONObject 31 | 32 | init(json: JSONObject) { 33 | self.json = json 34 | } 35 | 36 | var name: String? { 37 | return json["name"] as? String 38 | } 39 | 40 | var name_highlighted: String? { 41 | return SearchResults.highlightResult(hit: json, path: "name")?.value 42 | } 43 | 44 | var imageUrl: URL? { 45 | guard let imagePath = json["image_path"] as? String else { 46 | return nil 47 | } 48 | return URL(string: "https://image.tmdb.org/t/p/w300" + imagePath) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/ActorCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import UIKit 25 | 26 | 27 | /// A collection view displaying a movie. 28 | /// 29 | class ActorCell: UITableViewCell { 30 | @IBOutlet weak var portraitImageView: UIImageView! 31 | @IBOutlet weak var nameLabel: UILabel! 32 | 33 | static let placeholder = UIImage(named: "placeholder")! 34 | 35 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 36 | super.init(style: style, reuseIdentifier: reuseIdentifier) 37 | } 38 | 39 | required init?(coder aDecoder: NSCoder) { 40 | super.init(coder: aDecoder) 41 | } 42 | 43 | override func awakeFromNib() { 44 | portraitImageView.layer.cornerRadius = portraitImageView.frame.height / 2 45 | portraitImageView.layer.masksToBounds = true 46 | } 47 | 48 | var actor: Actor? { 49 | didSet { 50 | nameLabel.highlightedText = actor?.name_highlighted 51 | if let url = actor?.imageUrl { 52 | portraitImageView.setImageWith(url, placeholderImage: ActorCell.placeholder) 53 | } else { 54 | portraitImageView.cancelImageDownloadTask() 55 | portraitImageView.image = ActorCell.placeholder 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/AlgoliaManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import AFNetworking 25 | import AlgoliaSearch 26 | import Foundation 27 | 28 | 29 | private let DEFAULTS_KEY_MIRRORED = "algolia.mirrored" 30 | private let DEFAULTS_KEY_STRATEGY = "algolia.requestStrategy" 31 | private let DEFAULTS_KEY_TIMEOUT = "algolia.offlineFallbackTimeout" 32 | 33 | 34 | class AlgoliaManager: NSObject { 35 | /// The singleton instance. 36 | static let sharedInstance = AlgoliaManager() 37 | 38 | let client: Client 39 | var actorsIndex: Index 40 | var moviesIndex: Index 41 | 42 | private override init() { 43 | let apiKey = Bundle.main.infoDictionary!["AlgoliaApiKey"] as! String 44 | client = Client(appID: "latency", apiKey: apiKey) 45 | actorsIndex = client.index(withName: "actors") 46 | moviesIndex = client.index(withName: "movies") 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import Reachability 25 | import UIKit 26 | 27 | @UIApplicationMain 28 | class AppDelegate: UIResponder, UIApplicationDelegate { 29 | 30 | static let colorForLocalOrigin = UIColor(red: 0.9, green: 0.97, blue: 1.0, alpha: 1.0) 31 | 32 | var window: UIWindow? 33 | 34 | var reachability: Reachability! 35 | 36 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 37 | // Listen for network reachability changes. 38 | self.reachability = Reachability.forInternetConnection() 39 | self.reachability.reachableBlock = { 40 | (reachability: Reachability?) -> Void in 41 | // Nothing to do 42 | } 43 | self.reachability.unreachableBlock = { 44 | (reachability: Reachability?) -> Void in 45 | // Nothing to do 46 | } 47 | self.reachability.startNotifier() 48 | 49 | // Set up an on-disk URL cache. 50 | let urlCache = URLCache(memoryCapacity: 0, diskCapacity:50 * 1024 * 1024, diskPath:nil) 51 | URLCache.shared = urlCache 52 | 53 | return true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Source/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Source/Base.lproj/Main_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 110 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 146 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 202 | 203 | 204 | 205 | 206 | 216 | 226 | 236 | 246 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 312 | 316 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | -------------------------------------------------------------------------------- /Source/ConfigViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import AlgoliaSearch 25 | import UIKit 26 | 27 | 28 | class ConfigViewController: UIViewController { 29 | var manager: AlgoliaManager! 30 | 31 | // MARK: - View lifecycle 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | 36 | manager = AlgoliaManager.sharedInstance 37 | 38 | update() 39 | } 40 | 41 | deinit { 42 | } 43 | 44 | // MARK: - State 45 | 46 | private func update() { 47 | } 48 | 49 | // MARK: - Actions 50 | 51 | @IBAction func done(_ sender: AnyObject) { 52 | self.dismiss(animated: true, completion: nil) 53 | } 54 | 55 | // MARK: - KVO 56 | 57 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/ConfigViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 25 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Source/GenreCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import InstantSearchCore 25 | import UIKit 26 | 27 | 28 | /// A collection view displaying a movie. 29 | /// 30 | class GenreCell: UITableViewCell { 31 | @IBOutlet weak var nameLabel: UILabel! 32 | @IBOutlet weak var countLabel: UILabel! 33 | 34 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 35 | super.init(style: style, reuseIdentifier: reuseIdentifier) 36 | } 37 | 38 | required init?(coder aDecoder: NSCoder) { 39 | super.init(coder: aDecoder) 40 | } 41 | 42 | override func awakeFromNib() { 43 | countLabel.textColor = countLabel.tintColor 44 | } 45 | 46 | var value: FacetValue? { 47 | didSet { 48 | nameLabel.text = value?.value 49 | countLabel.text = value != nil ? String(value!.count) : nil 50 | } 51 | } 52 | 53 | var checked: Bool = false { 54 | didSet { 55 | nameLabel.font = checked ? UIFont.boldSystemFont(ofSize: nameLabel.font.pointSize) : UIFont.systemFont(ofSize: nameLabel.font.pointSize) 56 | nameLabel.textColor = checked ? nameLabel.tintColor : UIColor.black 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import InstantSearchCore 25 | import UIKit 26 | 27 | extension UILabel { 28 | var highlightedText: String? { 29 | get { 30 | return attributedText?.string 31 | } 32 | set { 33 | let color = highlightedTextColor ?? self.tintColor ?? UIColor.blue 34 | attributedText = newValue == nil ? nil : Highlighter(highlightAttrs: [NSForegroundColorAttributeName: color]).render(text: newValue!) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Small@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-Small@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Small-40@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Small-40@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-60@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-60@3x.png", 37 | "scale" : "3x" 38 | } 39 | ], 40 | "info" : { 41 | "version" : 1, 42 | "author" : "xcode" 43 | } 44 | } -------------------------------------------------------------------------------- /Source/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Source/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /Source/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Source/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /Source/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Source/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /Source/Images.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Source/Images.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /Source/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Source/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /Source/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Source/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Source/Images.xcassets/white.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "white.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Source/Images.xcassets/white.imageset/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/Source/Images.xcassets/white.imageset/white.jpg -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIMainStoryboardFile~ipad 30 | Main_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UIRequiresFullScreen 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | 41 | AlgoliaApiKey 42 | ${ALGOLIA_API_KEY} 43 | AlgoliaOfflineSdkLicenseKey 44 | ${ALGOLIA_OFFLINE_SDK_LICENSE_KEY} 45 | UISupportedInterfaceOrientations~ipad 46 | 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Source/MovieCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import UIKit 25 | 26 | 27 | /// A collection view displaying a movie. 28 | /// 29 | class MovieCell: UICollectionViewCell { 30 | @IBOutlet weak var posterImageView: UIImageView! 31 | @IBOutlet weak var titleLabel: UILabel! 32 | 33 | static let placeholder = UIImage(named: "placeholder")! 34 | 35 | override init(frame: CGRect) { 36 | super.init(frame: frame) 37 | } 38 | 39 | required init?(coder aDecoder: NSCoder) { 40 | super.init(coder: aDecoder) 41 | } 42 | 43 | var movie: MovieRecord? { 44 | didSet { 45 | titleLabel.highlightedText = movie?.title_highlighted 46 | if let url = movie?.imageUrl { 47 | posterImageView.setImageWith(url, placeholderImage: MovieCell.placeholder) 48 | } else { 49 | posterImageView.cancelImageDownloadTask() 50 | posterImageView.image = MovieCell.placeholder 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Source/MovieRecord.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import AlgoliaSearch 25 | import InstantSearchCore 26 | import Foundation 27 | 28 | 29 | struct MovieRecord { 30 | private let json: JSONObject 31 | 32 | init(json: JSONObject) { 33 | self.json = json 34 | } 35 | 36 | var title: String? { 37 | return json["title"] as? String 38 | } 39 | 40 | var imageUrl: URL? { 41 | guard let urlString = json["image"] as? String else { 42 | return nil 43 | } 44 | return URL(string: urlString) 45 | } 46 | 47 | var title_highlighted: String? { 48 | return SearchResults.highlightResult(hit: json, path: "title")?.value 49 | } 50 | 51 | var rating: Int? { 52 | return json["rating"] as? Int 53 | } 54 | 55 | var year: Int? { 56 | return json["year"] as? Int 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Source/MoviesIpadViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import AlgoliaSearch 25 | import InstantSearchCore 26 | import TTRangeSlider 27 | import UIKit 28 | 29 | class MoviesIpadViewController: UIViewController, UICollectionViewDataSource, TTRangeSliderDelegate, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate, SearchProgressDelegate { 30 | @IBOutlet weak var searchBar: UISearchBar! 31 | @IBOutlet weak var genreTableView: UITableView! 32 | @IBOutlet weak var yearRangeSlider: TTRangeSlider! 33 | @IBOutlet weak var ratingSelectorView: RatingSelectorView! 34 | @IBOutlet weak var moviesCollectionView: UICollectionView! 35 | @IBOutlet weak var actorsTableView: UITableView! 36 | @IBOutlet weak var movieCountLabel: UILabel! 37 | @IBOutlet weak var searchTimeLabel: UILabel! 38 | @IBOutlet weak var genreTableViewFooter: UILabel! 39 | @IBOutlet weak var genreFilteringModeSwitch: UISwitch! 40 | @IBOutlet weak var activityIndicator: UIActivityIndicatorView! 41 | 42 | var actorSearcher: Searcher! 43 | var movieSearcher: Searcher! 44 | var actorHits: [JSONObject] = [] 45 | var movieHits: [JSONObject] = [] 46 | var genreFacets: [FacetValue] = [] 47 | 48 | var yearFilterDebouncer = Debouncer(delay: 0.3) 49 | var searchProgressController: SearchProgressController! 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | self.movieCountLabel.text = NSLocalizedString("movie_count_placeholder", comment: "") 55 | self.searchTimeLabel.text = nil 56 | 57 | // Customize search bar. 58 | searchBar.placeholder = NSLocalizedString("search_bar_placeholder", comment: "") 59 | 60 | // Customize year range slider. 61 | yearRangeSlider.numberFormatterOverride = NumberFormatter() 62 | let tintColor = self.view.tintColor 63 | yearRangeSlider.tintColorBetweenHandles = tintColor 64 | yearRangeSlider.handleColor = tintColor 65 | yearRangeSlider.lineHeight = 3 66 | yearRangeSlider.minLabelFont = UIFont.systemFont(ofSize: 12) 67 | yearRangeSlider.maxLabelFont = yearRangeSlider.minLabelFont 68 | 69 | ratingSelectorView.addObserver(self, forKeyPath: "rating", options: .new, context: nil) 70 | 71 | // Customize genre table view. 72 | genreTableView.tableFooterView = genreTableViewFooter 73 | genreTableViewFooter.isHidden = true 74 | 75 | // Configure actor search. 76 | actorSearcher = Searcher(index: AlgoliaManager.sharedInstance.actorsIndex, resultHandler: self.handleActorSearchResults) 77 | actorSearcher.params.hitsPerPage = 10 78 | actorSearcher.params.attributesToHighlight = ["name"] 79 | 80 | // Configure movie search. 81 | movieSearcher = Searcher(index: AlgoliaManager.sharedInstance.moviesIndex, resultHandler: self.handleMovieSearchResults) 82 | movieSearcher.params.facets = ["genre"] 83 | movieSearcher.params.attributesToHighlight = ["title"] 84 | movieSearcher.params.hitsPerPage = 30 85 | 86 | // Configure search progress monitoring. 87 | searchProgressController = SearchProgressController(searcher: movieSearcher) 88 | searchProgressController.graceDelay = 0.5 89 | searchProgressController.delegate = self 90 | 91 | search() 92 | } 93 | 94 | deinit { 95 | NotificationCenter.default.removeObserver(self) 96 | } 97 | 98 | override func didReceiveMemoryWarning() { 99 | super.didReceiveMemoryWarning() 100 | } 101 | 102 | // MARK: - Actions 103 | 104 | private func search() { 105 | actorSearcher.search() 106 | movieSearcher.params.setFacet(withName: "genre", disjunctive: genreFilteringModeSwitch.isOn) 107 | movieSearcher.params.clearNumericRefinements() 108 | movieSearcher.params.addNumericRefinement("year", .greaterThanOrEqual, Int(yearRangeSlider.selectedMinimum)) 109 | movieSearcher.params.addNumericRefinement("year", .lessThanOrEqual, Int(yearRangeSlider.selectedMaximum)) 110 | movieSearcher.params.addNumericRefinement("rating", .greaterThanOrEqual, ratingSelectorView.rating) 111 | movieSearcher.search() 112 | } 113 | 114 | @IBAction func genreFilteringModeDidChange(_ sender: AnyObject) { 115 | movieSearcher.params.setFacet(withName: "genre", disjunctive: genreFilteringModeSwitch.isOn) 116 | search() 117 | } 118 | 119 | @IBAction func configTapped(_ sender: AnyObject) { 120 | let vc = ConfigViewController(nibName: "ConfigViewController", bundle: nil) 121 | self.present(vc, animated: true, completion: nil) 122 | } 123 | 124 | // MARK: - UISearchBarDelegate 125 | 126 | func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { 127 | actorSearcher.params.query = searchText 128 | movieSearcher.params.query = searchText 129 | search() 130 | } 131 | 132 | // MARK: - Search completion handlers 133 | 134 | private func handleActorSearchResults(results: SearchResults?, error: Error?) { 135 | guard let results = results else { return } 136 | if results.page == 0 { 137 | actorHits = results.hits 138 | } else { 139 | actorHits.append(contentsOf: results.hits) 140 | } 141 | self.actorsTableView.reloadData() 142 | 143 | // Scroll to top. 144 | if results.page == 0 { 145 | self.moviesCollectionView.contentOffset = CGPoint.zero 146 | } 147 | } 148 | 149 | private func handleMovieSearchResults(results: SearchResults?, error: Error?) { 150 | guard let results = results else { 151 | self.searchTimeLabel.textColor = UIColor.red 152 | self.searchTimeLabel.text = NSLocalizedString("error_search", comment: "") 153 | return 154 | } 155 | if results.page == 0 { 156 | movieHits = results.hits 157 | } else { 158 | movieHits.append(contentsOf: results.hits) 159 | } 160 | // Sort facets: first selected facets, then by decreasing count, then by name. 161 | genreFacets = FacetValue.listFrom(facetCounts: results.facets(name: "genre"), refinements: movieSearcher.params.buildFacetRefinements()["genre"]).sorted() { (lhs, rhs) in 162 | // When using cunjunctive faceting ("AND"), all refined facet values are displayed first. 163 | // But when using disjunctive faceting ("OR"), refined facet values are left where they are. 164 | let disjunctiveFaceting = results.disjunctiveFacets.contains("genre") 165 | let lhsChecked = self.movieSearcher.params.hasFacetRefinement(name: "genre", value: lhs.value) 166 | let rhsChecked = self.movieSearcher.params.hasFacetRefinement(name: "genre", value: rhs.value) 167 | if !disjunctiveFaceting && lhsChecked != rhsChecked { 168 | return lhsChecked 169 | } else if lhs.count != rhs.count { 170 | return lhs.count > rhs.count 171 | } else { 172 | return lhs.value < rhs.value 173 | } 174 | } 175 | let exhaustiveFacetsCount = results.exhaustiveFacetsCount == true 176 | genreTableViewFooter.isHidden = exhaustiveFacetsCount 177 | 178 | let formatter = NumberFormatter() 179 | formatter.locale = NSLocale.current 180 | formatter.numberStyle = .decimal 181 | formatter.usesGroupingSeparator = true 182 | formatter.groupingSize = 3 183 | self.movieCountLabel.text = "\(formatter.string(for: results.nbHits)!) MOVIES" 184 | 185 | searchTimeLabel.textColor = UIColor.lightGray 186 | self.searchTimeLabel.text = "Found in \(results.processingTimeMS) ms" 187 | // Indicate origin of content. 188 | if results.content["origin"] as? String == "local" { 189 | searchTimeLabel.textColor = searchTimeLabel.highlightedTextColor 190 | searchTimeLabel.text! += " (offline results)" 191 | } 192 | 193 | self.genreTableView.reloadData() 194 | self.moviesCollectionView.reloadData() 195 | 196 | // Scroll to top. 197 | if results.page == 0 { 198 | self.moviesCollectionView.contentOffset = CGPoint.zero 199 | } 200 | } 201 | 202 | // MARK: - UICollectionViewDataSource 203 | 204 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 205 | return movieHits.count 206 | } 207 | 208 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 209 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "movieCell", for: indexPath) as! MovieCell 210 | cell.movie = MovieRecord(json: movieHits[indexPath.item]) 211 | if indexPath.item + 5 >= movieHits.count { 212 | movieSearcher.loadMore() 213 | } 214 | return cell 215 | } 216 | 217 | // MARK: - UITableViewDataSource 218 | 219 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 220 | switch tableView { 221 | case actorsTableView: return actorHits.count 222 | case genreTableView: return genreFacets.count 223 | default: assert(false); return 0 224 | } 225 | } 226 | 227 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 228 | switch tableView { 229 | case actorsTableView: 230 | let cell = tableView.dequeueReusableCell(withIdentifier: "actorCell", for: indexPath) as! ActorCell 231 | cell.actor = Actor(json: actorHits[indexPath.item]) 232 | if indexPath.item + 5 >= actorHits.count { 233 | actorSearcher.loadMore() 234 | } 235 | return cell 236 | case genreTableView: 237 | let cell = tableView.dequeueReusableCell(withIdentifier: "genreCell", for: indexPath) as! GenreCell 238 | cell.value = genreFacets[indexPath.item] 239 | cell.checked = movieSearcher.params.hasFacetRefinement(name: "genre", value: genreFacets[indexPath.item].value) 240 | return cell 241 | default: assert(false); return UITableViewCell() 242 | } 243 | } 244 | 245 | // MARK: - UITableViewDelegate 246 | 247 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 248 | switch tableView { 249 | case genreTableView: 250 | movieSearcher.params.toggleFacetRefinement(name: "genre", value: genreFacets[indexPath.item].value) 251 | movieSearcher.search() 252 | break 253 | default: return 254 | } 255 | } 256 | 257 | // MARK: - TTRangeSliderDelegate 258 | 259 | func rangeSlider(_ sender: TTRangeSlider!, didChangeSelectedMinimumValue selectedMinimum: Float, andMaximumValue selectedMaximum: Float) { 260 | yearFilterDebouncer.call { 261 | self.search() 262 | } 263 | } 264 | 265 | // MARK: - KVO 266 | 267 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 268 | guard let object = object as? NSObject else { return } 269 | if object === ratingSelectorView { 270 | if keyPath == "rating" { 271 | search() 272 | } 273 | } 274 | } 275 | 276 | // MARK: - SearchProgressDelegate 277 | 278 | func searchDidStart(_ searchProgressController: SearchProgressController) { 279 | UIApplication.shared.isNetworkActivityIndicatorVisible = true 280 | activityIndicator.startAnimating() 281 | } 282 | 283 | func searchDidStop(_ searchProgressController: SearchProgressController) { 284 | UIApplication.shared.isNetworkActivityIndicatorVisible = false 285 | activityIndicator.stopAnimating() 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /Source/MoviesTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import AlgoliaSearch 25 | import InstantSearchCore 26 | import AFNetworking 27 | import UIKit 28 | 29 | 30 | class MoviesTableViewController: UITableViewController, UISearchBarDelegate, UISearchResultsUpdating, SearchProgressDelegate { 31 | 32 | var searchController: UISearchController! 33 | var searchProgressController: SearchProgressController! 34 | 35 | var movieSearcher: Searcher! 36 | var movieHits: [JSONObject] = [] 37 | var originIsLocal: Bool = false 38 | 39 | let placeholder = UIImage(named: "white") 40 | 41 | override func viewDidLoad() { 42 | super.viewDidLoad() 43 | 44 | // Algolia Search 45 | movieSearcher = Searcher(index: AlgoliaManager.sharedInstance.moviesIndex, resultHandler: self.handleSearchResults) 46 | movieSearcher.params.hitsPerPage = 15 47 | movieSearcher.params.attributesToRetrieve = ["title", "image", "rating", "year"] 48 | movieSearcher.params.attributesToHighlight = ["title"] 49 | 50 | // Search controller 51 | searchController = UISearchController(searchResultsController: nil) 52 | searchController.searchResultsUpdater = self 53 | searchController.dimsBackgroundDuringPresentation = false 54 | searchController.searchBar.delegate = self 55 | searchController.searchBar.placeholder = NSLocalizedString("search_bar_placeholder", comment: "") 56 | 57 | // Add the search bar 58 | tableView.tableHeaderView = self.searchController!.searchBar 59 | definesPresentationContext = true 60 | searchController!.searchBar.sizeToFit() 61 | 62 | // Configure search progress monitoring. 63 | searchProgressController = SearchProgressController(searcher: movieSearcher) 64 | searchProgressController.delegate = self 65 | 66 | // First load 67 | updateSearchResults(for: searchController) 68 | } 69 | 70 | deinit { 71 | NotificationCenter.default.removeObserver(self) 72 | } 73 | 74 | override func didReceiveMemoryWarning() { 75 | super.didReceiveMemoryWarning() 76 | // Dispose of any resources that can be recreated. 77 | } 78 | 79 | // MARK: - Actions 80 | 81 | @IBAction func configTapped(_ sender: AnyObject) { 82 | let vc = ConfigViewController(nibName: "ConfigViewController", bundle: nil) 83 | self.present(vc, animated: true, completion: nil) 84 | } 85 | 86 | // MARK: - Search completion handlers 87 | 88 | private func handleSearchResults(results: SearchResults?, error: Error?) { 89 | guard let results = results else { return } 90 | if results.page == 0 { 91 | movieHits = results.hits 92 | } else { 93 | movieHits.append(contentsOf: results.hits) 94 | } 95 | originIsLocal = results.content["origin"] as? String == "local" 96 | self.tableView.reloadData() 97 | } 98 | 99 | // MARK: - Table view data source 100 | 101 | override func numberOfSections(in tableView: UITableView) -> Int { 102 | return 1 103 | } 104 | 105 | override func tableView(_ tableView: UITableView, numberOfRowsInSection: Int) -> Int { 106 | return movieHits.count 107 | } 108 | 109 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 110 | let cell = tableView.dequeueReusableCell(withIdentifier: "movieCell", for: indexPath) 111 | 112 | // Load more? 113 | if indexPath.row + 5 >= movieHits.count { 114 | movieSearcher.loadMore() 115 | } 116 | 117 | // Configure the cell... 118 | let movie = MovieRecord(json: movieHits[indexPath.row]) 119 | cell.textLabel?.highlightedText = movie.title_highlighted 120 | 121 | cell.detailTextLabel?.text = movie.year != nil ? "\(movie.year!)" : nil 122 | cell.imageView?.cancelImageDownloadTask() 123 | if let url = movie.imageUrl { 124 | cell.imageView?.setImageWith(url, placeholderImage: placeholder) 125 | } 126 | else { 127 | cell.imageView?.image = nil 128 | } 129 | cell.backgroundColor = originIsLocal ? AppDelegate.colorForLocalOrigin : UIColor.white 130 | 131 | return cell 132 | } 133 | 134 | // MARK: - Search 135 | 136 | func updateSearchResults(for searchController: UISearchController) { 137 | movieSearcher.params.query = searchController.searchBar.text 138 | movieSearcher.search() 139 | } 140 | 141 | // MARK: - KVO 142 | 143 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 144 | } 145 | 146 | // MARK: - Activity indicator 147 | 148 | // MARK: - SearchProgressDelegate 149 | 150 | func searchDidStart(_ searchProgressController: SearchProgressController) { 151 | UIApplication.shared.isNetworkActivityIndicatorVisible = true 152 | } 153 | 154 | func searchDidStop(_ searchProgressController: SearchProgressController) { 155 | UIApplication.shared.isNetworkActivityIndicatorVisible = false 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /Source/RatingSelectorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import Foundation 25 | import UIKit 26 | 27 | 28 | class RatingSelectorView: UIView { 29 | @IBOutlet weak var star1Button: UIButton! 30 | @IBOutlet weak var star2Button: UIButton! 31 | @IBOutlet weak var star3Button: UIButton! 32 | @IBOutlet weak var star4Button: UIButton! 33 | @IBOutlet weak var star5Button: UIButton! 34 | 35 | private var buttons: [UIButton] = [] 36 | 37 | var rating: Int = 0 { 38 | willSet { 39 | willChangeValue(forKey: "rating") 40 | } 41 | didSet { 42 | didChangeValue(forKey: "rating") 43 | update() 44 | } 45 | } 46 | 47 | override func awakeFromNib() { 48 | buttons = [star1Button, star2Button, star3Button, star4Button, star5Button] 49 | update() 50 | } 51 | 52 | @IBAction func didPressStar(_ sender: UIButton) { 53 | rating = buttons.index(of: sender)! + 1 54 | } 55 | 56 | private func update() { 57 | for i in 0..= rating 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/MovieSearchTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Algolia 3 | // http://www.algolia.com/ 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | // 23 | 24 | import UIKit 25 | import XCTest 26 | 27 | class MovieSearchTests: XCTestCase { 28 | 29 | override func setUp() { 30 | super.setUp() 31 | // Put setup code here. This method is called before the invocation of each test method in the class. 32 | } 33 | 34 | override func tearDown() { 35 | // Put teardown code here. This method is called after the invocation of each test method in the class. 36 | super.tearDown() 37 | } 38 | 39 | func testExample() { 40 | // This is an example of a functional test case. 41 | XCTAssert(true, "Pass") 42 | } 43 | 44 | func testPerformanceExample() { 45 | // This is an example of a performance test case. 46 | self.measureBlock() { 47 | // Put the code you want to measure the time of here. 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /iOS_instant_search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algolia-swift-demo/7a46edf8aa6b4c7a084bdf4643a2c30e37e55c0d/iOS_instant_search.gif --------------------------------------------------------------------------------