├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ └── dependabot-alerts-to-slack.yml ├── .gitignore ├── .jazzy.yaml ├── .slather.yml ├── .swiftlint.auto.yml ├── .swiftlint.yml ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── AutocompleteClient.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── xcshareddata │ └── xcschemes │ └── ConstructorAutocomplete.xcscheme ├── AutocompleteClient.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings ├── AutocompleteClient ├── Constants │ └── Constants.swift ├── ConstructorAutocomplete-Swift.h ├── FW │ ├── API │ │ ├── Data │ │ │ └── TaskResponse.swift │ │ ├── Error │ │ │ └── NSError+Errors.swift │ │ ├── Network │ │ │ ├── Client │ │ │ │ ├── NetworkClient.swift │ │ │ │ └── URLSessionNetworkClient.swift │ │ │ └── Response │ │ │ │ ├── AutocompleteTaskResponse.swift │ │ │ │ ├── BrowseFacetOptionsTaskResponse.swift │ │ │ │ ├── BrowseFacetsTaskResponse.swift │ │ │ │ ├── BrowseTaskResponse.swift │ │ │ │ ├── NetworkResponse.swift │ │ │ │ ├── QuizQuestionTaskResponse.swift │ │ │ │ ├── QuizResultsTaskResponse.swift │ │ │ │ ├── RecommendationsTaskResponse.swift │ │ │ │ ├── SearchTaskResponse.swift │ │ │ │ └── TrackingTaskResponse.swift │ │ └── Parser │ │ │ ├── Autocomplete │ │ │ ├── AbstractAutocompleteResponseParser.swift │ │ │ ├── CIOAutocompleteResponseParser.swift │ │ │ └── ResponseParserDelegate.swift │ │ │ ├── Browse │ │ │ ├── AbstractBrowseFacetOptionsResponseParser.swift │ │ │ ├── AbstractBrowseFacetsResponseParser.swift │ │ │ ├── AbstractBrowseResponseParser.swift │ │ │ ├── BrowseFacetOptionsResponseParser.swift │ │ │ ├── BrowseFacetsResponseParser.swift │ │ │ └── BrowseResponseParser.swift │ │ │ ├── Quizzes │ │ │ ├── AbstractQuizQuestionResponseParser.swift │ │ │ ├── AbstractQuizResultsResponseParser.swift │ │ │ ├── QuizQuestionResponseParser.swift │ │ │ └── QuizResultsResponseParser.swift │ │ │ ├── Recommendations │ │ │ ├── AbstractRecommendationsResponseParser.swift │ │ │ └── RecommendationsResponseParser.swift │ │ │ └── Search │ │ │ ├── AbstractSearchResponseParser.swift │ │ │ └── SearchResponseParser.swift │ ├── Config │ │ ├── AutocompleteResultCount.swift │ │ └── ConstructorIOConfig.swift │ ├── DependencyInjection │ │ └── DependencyContainer.swift │ ├── Logging │ │ ├── CIOLogger.swift │ │ └── CIOPrintLogger.swift │ ├── Logic │ │ ├── ABTesting │ │ │ └── CIOABTestCell.swift │ │ ├── ClientID │ │ │ ├── ClientIDGenerator.swift │ │ │ ├── IDGenerator.swift │ │ │ └── Persistence │ │ │ │ ├── CIOClientIdLoader.swift │ │ │ │ └── ClientIdLoader.swift │ │ ├── Error │ │ │ └── CIOError.swift │ │ ├── Highlighting │ │ │ ├── Attributes │ │ │ │ ├── BoldAttributesProvider.swift │ │ │ │ └── CIOHighlightingAttributesProvider.swift │ │ │ └── CIOHighlighter.swift │ │ ├── Query │ │ │ ├── CIOQueryFilters.swift │ │ │ ├── CIOQueryFmtOptions.swift │ │ │ └── CIOQueryVariationsMap.swift │ │ ├── Request │ │ │ ├── Builder │ │ │ │ ├── CIOAutocompleteQueryBuilder.swift │ │ │ │ ├── CIOBrowseFacetOptionsQueryBuilder.swift │ │ │ │ ├── CIOBrowseFacetsQueryBuilder.swift │ │ │ │ ├── CIOBrowseGroupsQueryBuilder.swift │ │ │ │ ├── CIOBrowseItemsQueryBuilder.swift │ │ │ │ ├── CIOBrowseQueryBuilder.swift │ │ │ │ ├── CIORecommendationsQueryBuilder.swift │ │ │ │ ├── CIOSearchQueryBuilder.swift │ │ │ │ ├── QueryItemCollection.swift │ │ │ │ ├── RequestBuilder+QueryItems.swift │ │ │ │ └── RequestBuilder.swift │ │ │ ├── CIOAutocompleteQuery.swift │ │ │ ├── CIOBrowseFacetOptionsQuery.swift │ │ │ ├── CIOBrowseFacetsQuery.swift │ │ │ ├── CIOBrowseGroupsQuery.swift │ │ │ ├── CIOBrowseItemsQuery.swift │ │ │ ├── CIOBrowseQuery.swift │ │ │ ├── CIOGroupsSortOption.swift │ │ │ ├── CIOItem.swift │ │ │ ├── CIOQuizQuery.swift │ │ │ ├── CIORecommendationsQuery.swift │ │ │ ├── CIORequestData.swift │ │ │ ├── CIOSearchQuery.swift │ │ │ ├── CIOTrackAutocompleteSelectData.swift │ │ │ ├── CIOTrackBrowseResultClickData.swift │ │ │ ├── CIOTrackBrowseResultsLoadedData.swift │ │ │ ├── CIOTrackConversionData.swift │ │ │ ├── CIOTrackInputFocusData.swift │ │ │ ├── CIOTrackItemDetailLoadData.swift │ │ │ ├── CIOTrackPurchaseData.swift │ │ │ ├── CIOTrackQuizConversionData.swift │ │ │ ├── CIOTrackQuizResultClickData.swift │ │ │ ├── CIOTrackQuizResultsLoadedData.swift │ │ │ ├── CIOTrackRecommendationResultClickData.swift │ │ │ ├── CIOTrackRecommendationResultsViewData.swift │ │ │ ├── CIOTrackSearchResultClickData.swift │ │ │ ├── CIOTrackSearchResultsLoadedData.swift │ │ │ ├── CIOTrackSearchSubmitData.swift │ │ │ └── CIOTrackSessionStartData.swift │ │ ├── Result │ │ │ ├── CIOAutocompleteResult.swift │ │ │ ├── CIOCollectionData.swift │ │ │ ├── CIOFilterFacet.swift │ │ │ ├── CIOFilterFacetOption.swift │ │ │ ├── CIOFilterGroup.swift │ │ │ ├── CIOGroup.swift │ │ │ ├── CIOQuizImages.swift │ │ │ ├── CIOQuizOption.swift │ │ │ ├── CIOQuizOptionAttribute.swift │ │ │ ├── CIOQuizQuestion.swift │ │ │ ├── CIOQuizResult.swift │ │ │ ├── CIORecommendationsPod.swift │ │ │ ├── CIORecommendationsStrategy.swift │ │ │ ├── CIORefinedContent.swift │ │ │ ├── CIOResult.swift │ │ │ ├── CIOResultData.swift │ │ │ ├── CIOResultFacet.swift │ │ │ ├── CIOResultSourceData.swift │ │ │ ├── CIOResultSources.swift │ │ │ ├── CIOSearchRedirectInfo.swift │ │ │ ├── CIOSortOption.swift │ │ │ └── Responses │ │ │ │ ├── CIOAutocompleteResponse.swift │ │ │ │ ├── CIOBrowseFacetOptionsResponse.swift │ │ │ │ ├── CIOBrowseFacetsResponse.swift │ │ │ │ ├── CIOBrowseResponse.swift │ │ │ │ ├── CIOQuizQuestionResponse.swift │ │ │ │ ├── CIOQuizResultsResponse.swift │ │ │ │ ├── CIORecommendationsResponse.swift │ │ │ │ └── CIOSearchResponse.swift │ │ ├── Session │ │ │ ├── CIOSessionManager.swift │ │ │ ├── CIOSessionManagerDelegate.swift │ │ │ ├── Date │ │ │ │ ├── CurrentTimeDateProvider.swift │ │ │ │ └── DateProvider.swift │ │ │ ├── Persistence │ │ │ │ ├── CIOSessionLoader.swift │ │ │ │ └── SessionLoader.swift │ │ │ ├── Session.swift │ │ │ └── SessionManager.swift │ │ └── Worker │ │ │ └── ConstructorIO.swift │ └── UI │ │ ├── CIOAutocompleteViewController.swift │ │ ├── CustomCell │ │ └── SearchResultCell.swift │ │ ├── DefaultSearchItemCell.swift │ │ ├── DefaultSearchItemCell.xib │ │ ├── Delegate │ │ └── CIOAutocompleteDelegate.swift │ │ ├── Empty │ │ ├── EmptyScreenView.swift │ │ └── EmptyScreenView.xib │ │ ├── Error │ │ └── CIOErrorView.swift │ │ ├── SearchBar │ │ ├── CIOSearchBarDisplayMode.swift │ │ ├── CustomSearchBar.swift │ │ └── CustomSearchController.swift │ │ ├── Style │ │ └── CIOStyle.swift │ │ ├── UICustomization │ │ └── CIOAutocompleteUICustomization.swift │ │ └── ViewModel │ │ ├── AbstractAutocompleteViewModel.swift │ │ ├── AutocompleteResult.swift │ │ ├── AutocompleteViewModel.swift │ │ ├── AutocompleteViewModelDelegate.swift │ │ └── AutocompleteViewModelSection.swift ├── Info.plist ├── Resources │ ├── constructor-io-error-icon.png │ └── constructor-io-logo.png └── Utils │ ├── AutoLayout │ └── UIView+AutoLayout.swift │ ├── Collection │ └── Collection+MapKeys.swift │ ├── Color │ └── UIColor+RGB.swift │ ├── String │ ├── NSAttributedString+Build.swift │ ├── String+CharacterSetIterator.swift │ ├── String+SearchSuggestionsSection.swift │ └── String+Trim.swift │ └── UI │ ├── UISearchBar+TextField.swift │ ├── UIView+FadeInOut.swift │ └── UIView+FindSubview.swift ├── AutocompleteClientTests ├── FW │ ├── API │ │ ├── Error │ │ │ └── ErrorTests.swift │ │ └── Parser │ │ │ ├── BrowseResponseParserTest.swift │ │ │ ├── CIOAutocompleteResponseParserTests.swift │ │ │ ├── MockResponseParserDelegate.swift │ │ │ ├── RecommendationsResponseParserTests.swift │ │ │ └── SearchResponseParserTests.swift │ ├── Logic │ │ ├── Highlighting │ │ │ └── CIOHighlighterTests.swift │ │ ├── Request │ │ │ ├── AutocompleteQueryRequestBuilderTests.swift │ │ │ ├── Matchers │ │ │ │ ├── CIOBuilder.swift │ │ │ │ └── Matcher+Regex.swift │ │ │ ├── Mock │ │ │ │ ├── AbstractAutocompleteViewModel+Mock.swift │ │ │ │ ├── CIOGroup+Mock.swift │ │ │ │ ├── CIOResult+Mock.swift │ │ │ │ └── MockCommons.swift │ │ │ ├── QueryItemCollection │ │ │ │ └── QueryItemCollectionTests.swift │ │ │ ├── QuizzesQueryRequestBuilderTests.swift │ │ │ ├── RecommendationsQueryRequestBuilderTests.swift │ │ │ ├── TrackAutocompleteSelectRequestBuilderTests.swift │ │ │ ├── TrackBrowseResultClickRequestBuilder.swift │ │ │ ├── TrackBrowseResultsLoadedRequestBuilder.swift │ │ │ ├── TrackConversionRequestBuilderTests.swift │ │ │ ├── TrackInputFocusRequestBuilderTests.swift │ │ │ ├── TrackItemDetailLoadRequestBuilder.swift │ │ │ ├── TrackPurchaseRequestBuilderTests.swift │ │ │ ├── TrackQuizConversionRequestBuilder.swift │ │ │ ├── TrackQuizResultClickRequestBuilder.swift │ │ │ ├── TrackQuizResultsLoadedRequestBuilder.swift │ │ │ ├── TrackRecommendationResultClickRequestBuilder.swift │ │ │ ├── TrackRecommendationViewRequestBuilder.swift │ │ │ ├── TrackSearchResultClickRequestBuilder.swift │ │ │ ├── TrackSearchResultsLoadedRequestBuilder.swift │ │ │ ├── TrackSearchSubmitRequestBuilder.swift │ │ │ └── TrackSessionStartRequestBuilder.swift │ │ ├── Session │ │ │ ├── ClosureDateProvider.swift │ │ │ ├── ClosureSessionManagerDelegate.swift │ │ │ ├── NoSessionLoader.swift │ │ │ └── SessionManagerTests.swift │ │ └── Worker │ │ │ ├── ConstructorIOABTestCellTests.swift │ │ │ ├── ConstructorIOAutocompleteTests.swift │ │ │ ├── ConstructorIOBrowseFacetOptionsTests.swift │ │ │ ├── ConstructorIOBrowseFacetsTests.swift │ │ │ ├── ConstructorIOBrowseGroupsTests.swift │ │ │ ├── ConstructorIOBrowseItemsTests.swift │ │ │ ├── ConstructorIOBrowseTests.swift │ │ │ ├── ConstructorIOIntegrationTests.swift │ │ │ ├── ConstructorIOQuizIntegrationTests.swift │ │ │ ├── ConstructorIOQuizTests.swift │ │ │ ├── ConstructorIORecommendationsTests.swift │ │ │ ├── ConstructorIOSearchTests.swift │ │ │ ├── ConstructorIOTests.swift │ │ │ ├── ConstructorIOTrackAutocompleteSelectTests.swift │ │ │ ├── ConstructorIOTrackBrowseResultClickTests.swift │ │ │ ├── ConstructorIOTrackBrowseResultsLoadedTests.swift │ │ │ ├── ConstructorIOTrackConversionTests.swift │ │ │ ├── ConstructorIOTrackInputFocusTests.swift │ │ │ ├── ConstructorIOTrackItemDetailLoadTests.swift │ │ │ ├── ConstructorIOTrackPurchaseTests.swift │ │ │ ├── ConstructorIOTrackQuizConversionTests.swift │ │ │ ├── ConstructorIOTrackQuizResultClick.swift │ │ │ ├── ConstructorIOTrackQuizResultsLoadedTests.swift │ │ │ ├── ConstructorIOTrackRecommendationResultClickTests.swift │ │ │ ├── ConstructorIOTrackRecommendationResultsViewTests.swift │ │ │ ├── ConstructorIOTrackSearchResultClickTests.swift │ │ │ ├── ConstructorIOTrackSearchResultsLoadedTests.swift │ │ │ ├── ConstructorIOTrackSearchSubmitTests.swift │ │ │ ├── ConstructorIOUserIDTests.swift │ │ │ ├── ConstructorIOUserSegmentsTests.swift │ │ │ └── SearchTests.swift │ └── UI │ │ ├── Other │ │ └── DefaultSearchItemCellTests.swift │ │ ├── SearchBar │ │ └── SearchBarTextFieldTests.swift │ │ ├── ViewController │ │ └── AutocompleteViewControllerTests.swift │ │ └── ViewModel │ │ ├── AutocompleteResultCountTests.swift │ │ ├── AutocompleteResultTests.swift │ │ ├── AutocompleteViewModelTests.swift │ │ └── ClosureAutocompleteViewModelDelegate.swift ├── Info.plist ├── Resources │ ├── TestResource.swift │ ├── response_browse_facet_options_json.json │ ├── response_browse_facets_json.json │ ├── response_browse_json.json │ ├── response_json_multiple_groups.json │ ├── response_json_multiple_sections.json │ ├── response_json_single_result.json │ ├── response_json_single_section.json │ ├── response_quiz_next_question.json │ ├── response_quiz_results.json │ ├── response_recommendations.json │ ├── response_search_json.json │ ├── response_search_json_invalid_variations.json │ ├── response_search_json_refined_content.json │ ├── response_search_json_variation_custom_data.json │ ├── response_search_json_variations.json │ └── response_search_redirect.json ├── Test Utils │ ├── Bundle │ │ └── Bundle+Test.swift │ ├── CIOResponse+SearchSuggestions.swift │ ├── Constants │ │ └── TestConstants.swift │ ├── JSON │ │ └── Data+ToJSON.swift │ └── XCTest │ │ ├── ExpectationHandler.swift │ │ └── XCTest+TimeoutFail.swift └── Utils │ ├── Color │ └── UIColorRGBConversionTests.swift │ ├── String │ ├── NSString+RangeOfCharactersTest.swift │ ├── SearchSuggestionStringConversionTests.swift │ ├── String+CharacterSetIteratorTests.swift │ └── StringTrimTests.swift │ └── UI │ └── UIViewAnimationTests.swift ├── ConstructorAutocomplete.d ├── ConstructorAutocomplete.dia ├── ConstructorAutocomplete.podspec ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Package.swift ├── Podfile ├── Podfile.lock ├── Pods ├── Kingfisher │ ├── LICENSE │ ├── README.md │ └── Sources │ │ ├── AnimatedImageView.swift │ │ ├── Box.swift │ │ ├── CacheSerializer.swift │ │ ├── Filter.swift │ │ ├── FormatIndicatedCacheSerializer.swift │ │ ├── Image.swift │ │ ├── ImageCache.swift │ │ ├── ImageDownloader.swift │ │ ├── ImageModifier.swift │ │ ├── ImagePrefetcher.swift │ │ ├── ImageProcessor.swift │ │ ├── ImageTransition.swift │ │ ├── ImageView+Kingfisher.swift │ │ ├── Indicator.swift │ │ ├── Kingfisher.h │ │ ├── Kingfisher.swift │ │ ├── KingfisherManager.swift │ │ ├── KingfisherOptionsInfo.swift │ │ ├── Placeholder.swift │ │ ├── RequestModifier.swift │ │ ├── Resource.swift │ │ ├── String+MD5.swift │ │ ├── ThreadHelper.swift │ │ └── UIButton+Kingfisher.swift ├── Manifest.lock ├── OHHTTPStubs │ ├── LICENSE │ ├── OHHTTPStubs │ │ └── Sources │ │ │ ├── Compatibility.h │ │ │ ├── JSON │ │ │ ├── OHHTTPStubsResponse+JSON.h │ │ │ └── OHHTTPStubsResponse+JSON.m │ │ │ ├── NSURLSession │ │ │ ├── NSURLRequest+HTTPBodyTesting.h │ │ │ ├── NSURLRequest+HTTPBodyTesting.m │ │ │ ├── OHHTTPStubs+NSURLSessionConfiguration.m │ │ │ ├── OHHTTPStubsMethodSwizzling.h │ │ │ └── OHHTTPStubsMethodSwizzling.m │ │ │ ├── OHHTTPStubs.h │ │ │ ├── OHHTTPStubs.m │ │ │ ├── OHHTTPStubsResponse.h │ │ │ ├── OHHTTPStubsResponse.m │ │ │ ├── OHPathHelpers │ │ │ ├── OHPathHelpers.h │ │ │ └── OHPathHelpers.m │ │ │ └── Swift │ │ │ └── OHHTTPStubsSwift.swift │ └── README.md ├── Pods.xcodeproj │ └── project.pbxproj └── Target Support Files │ ├── Kingfisher │ ├── Kingfisher-Info.plist │ ├── Kingfisher-dummy.m │ ├── Kingfisher-prefix.pch │ ├── Kingfisher-umbrella.h │ ├── Kingfisher.modulemap │ └── Kingfisher.xcconfig │ ├── OHHTTPStubs │ ├── Info.plist │ ├── OHHTTPStubs-Info.plist │ ├── OHHTTPStubs-dummy.m │ ├── OHHTTPStubs-prefix.pch │ ├── OHHTTPStubs-umbrella.h │ ├── OHHTTPStubs.modulemap │ └── OHHTTPStubs.xcconfig │ ├── Pods-AutocompleteClientTests │ ├── Info.plist │ ├── Pods-AutocompleteClientTests-Info.plist │ ├── Pods-AutocompleteClientTests-acknowledgements.markdown │ ├── Pods-AutocompleteClientTests-acknowledgements.plist │ ├── Pods-AutocompleteClientTests-dummy.m │ ├── Pods-AutocompleteClientTests-frameworks.sh │ ├── Pods-AutocompleteClientTests-resources.sh │ ├── Pods-AutocompleteClientTests-umbrella.h │ ├── Pods-AutocompleteClientTests.debug.xcconfig │ ├── Pods-AutocompleteClientTests.modulemap │ └── Pods-AutocompleteClientTests.release.xcconfig │ └── Pods-UserApplication │ ├── Pods-UserApplication-Info.plist │ ├── Pods-UserApplication-acknowledgements.markdown │ ├── Pods-UserApplication-acknowledgements.plist │ ├── Pods-UserApplication-dummy.m │ ├── Pods-UserApplication-frameworks.sh │ ├── Pods-UserApplication-umbrella.h │ ├── Pods-UserApplication.debug.xcconfig │ ├── Pods-UserApplication.modulemap │ └── Pods-UserApplication.release.xcconfig ├── PrivacyInfo.xcprivacy ├── README.md ├── Resources ├── Assets.xcassets │ ├── Contents.json │ ├── icon_empty.imageset │ │ ├── Contents.json │ │ ├── icon_constructor.png │ │ ├── icon_constructor@2x.png │ │ └── icon_constructor@3x.png │ └── icon_error.imageset │ │ ├── Contents.json │ │ ├── icon_error.png │ │ ├── icon_error@2x.png │ │ └── icon_error@3x.png └── constructor-io-error-icon.png ├── SearchFWTestApp ├── SearchFWTestApp.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── SearchFWTestApp │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── Logo │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift └── SearchFWTestAppTests │ ├── Info.plist │ └── SearchFWTestAppTests.swift ├── UserApplication ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── icon_cart.imageset │ │ ├── Contents.json │ │ ├── icon_cart.png │ │ ├── icon_cart@2x.png │ │ └── icon_cart@3x.png │ ├── icon_clock.imageset │ │ ├── Contents.json │ │ └── icon_clock.png │ ├── icon_error_yellow.imageset │ │ ├── Contents.json │ │ └── icon_error_yellow.png │ ├── icon_filter.imageset │ │ ├── Contents.json │ │ └── icon_filter.png │ ├── icon_gear.imageset │ │ ├── Contents.json │ │ └── icon-gear.png │ ├── icon_help.imageset │ │ ├── Contents.json │ │ └── icon_help.png │ ├── icon_logo.imageset │ │ ├── Contents.json │ │ └── constructor-io-logo.png │ ├── icon_sign_error.imageset │ │ ├── Contents.json │ │ └── icon_sign_error.png │ ├── icon_sort.imageset │ │ ├── Contents.json │ │ └── icon_sort.jpg │ ├── icon_star.imageset │ │ ├── Contents.json │ │ └── icon_star.png │ ├── img_logo.imageset │ │ ├── Contents.json │ │ └── img_logo.png │ ├── sort_ascending.imageset │ │ ├── Contents.json │ │ └── arrow_up.png │ └── sort_descending.imageset │ │ ├── Contents.json │ │ └── arrow_down.png ├── Common │ ├── BadgeView.swift │ ├── CartBarButtonItem.swift │ └── Constructor │ │ └── ConstructorIOProvider.swift ├── CustomHighlighting │ └── CustomAttributesProvider.swift ├── CustomViews │ ├── Background │ │ └── CustomBackgroundView.xib │ ├── Cell │ │ ├── Class │ │ │ └── CustomTableViewCellTwo.swift │ │ └── Nib │ │ │ ├── CustomTableViewCellOne.swift │ │ │ └── CustomTableViewCellOne.xib │ └── Error │ │ ├── CustomErrorView.swift │ │ └── CustomErrorView.xib ├── Info.plist ├── Screens │ ├── Cart │ │ ├── Logic │ │ │ ├── Cart.swift │ │ │ └── CartItem.swift │ │ ├── Persistence │ │ │ └── CartPersistence.swift │ │ ├── UI │ │ │ ├── CartItemTableViewCell.swift │ │ │ ├── CartItemTableViewCell.xib │ │ │ ├── CartViewController.swift │ │ │ └── CartViewController.xib │ │ └── ViewModel │ │ │ ├── CartItemViewModel.swift │ │ │ ├── CartViewModel.swift │ │ │ └── Quantity.swift │ ├── Details │ │ ├── UI │ │ │ ├── DetailsViewController.swift │ │ │ └── DetailsViewController.xib │ │ └── ViewModel │ │ │ └── DetailsViewModel.swift │ ├── Filters │ │ ├── Delegate │ │ │ └── FiltersSelectionDelegate.swift │ │ ├── UI │ │ │ ├── Cells │ │ │ │ ├── FilterTableViewCell.swift │ │ │ │ └── FilterTableViewCell.xib │ │ │ ├── Header │ │ │ │ ├── Delegate │ │ │ │ │ └── FilterHeaderDelegate.swift │ │ │ │ ├── FilterHeaderView.swift │ │ │ │ └── FilterHeaderView.xib │ │ │ └── ViewController │ │ │ │ ├── FiltersViewController.swift │ │ │ │ └── FiltersViewController.xib │ │ └── ViewModel │ │ │ ├── FacetOptionViewModel.swift │ │ │ ├── FacetViewModel.swift │ │ │ └── FiltersViewModel.swift │ ├── Search │ │ ├── UI │ │ │ ├── SearchCollectionViewCell.swift │ │ │ ├── SearchCollectionViewCell.xib │ │ │ ├── SearchTableViewCell.swift │ │ │ ├── SearchTableViewCell.xib │ │ │ ├── SearchViewController.swift │ │ │ └── SearchViewController.xib │ │ └── ViewModel │ │ │ ├── SearchResultViewModel.swift │ │ │ └── SearchViewModel.swift │ └── Sort │ │ ├── Delegate │ │ └── SortSelectionDelegate.swift │ │ ├── UI │ │ ├── SortOptionTableViewCell.swift │ │ ├── SortOptionTableViewCell.xib │ │ ├── SortOptionsViewController.swift │ │ ├── SortOptionsViewController.xib │ │ └── UIImage │ │ │ └── UIImage+Sort.swift │ │ └── ViewModel │ │ ├── SortOptionViewModel.swift │ │ └── SortViewModel.swift └── Utils │ └── UI │ ├── UIColor+RGB.swift │ ├── UIFont+AppFonts.swift │ └── UIView+AutoLayout.swift ├── UserApplicationTests ├── DataSource │ ├── AutocompleteDataSourceTests.swift │ └── AutocompleteDataSourceWrapper.swift ├── Delegate │ ├── AutocompleteDelegateTests.swift │ └── AutocompleteDelegateWrapper.swift ├── Info.plist └── Utils │ └── CIOAutocompleteViewController+Show.swift ├── coverage.all.sh ├── coverage.core.sh └── docs ├── Classes.html ├── Classes ├── AutocompleteResult.html ├── AutocompleteViewModel.html ├── BoldAttributesProvider.html ├── CIOAutocompleteQueryBuilder.html ├── CIOAutocompleteResult.html ├── CIOAutocompleteViewController.html ├── CIOBrowseFacetOptionsQueryBuilder.html ├── CIOBrowseFacetsQueryBuilder.html ├── CIOBrowseGroupsQueryBuilder.html ├── CIOBrowseItemsQueryBuilder.html ├── CIOBrowseQueryBuilder.html ├── CIOCollectionData.html ├── CIOFilterGroup.html ├── CIOGroup.html ├── CIOHighlighter.html ├── CIOPrintLogger.html ├── CIORecommendationsQueryBuilder.html ├── CIOResult.html ├── CIOResultSourceData.html ├── CIOResultSources.html ├── CIOSearchQueryBuilder.html ├── ConstructorIO.html ├── CustomSearchBar.html ├── CustomSearchController.html ├── DefaultSearchItemCell.html ├── EmptyScreenView.html ├── Session.html └── TaskResponse.html ├── Client.html ├── Constructor IO Client.html ├── Enums.html ├── Enums ├── CIOError.html ├── CIOSearchBarDisplayMode.html └── CIOSortOrder.html ├── Extensions.html ├── Extensions └── UISearchBar.html ├── Other Classes.html ├── Other Enums.html ├── Other Protocols.html ├── Other Structs.html ├── Protocols.html ├── Protocols ├── AbstractAutocompleteViewModel.html ├── AutocompleteViewModelDelegate.html ├── CIOAutocompleteCell.html ├── CIOAutocompleteDelegate.html ├── CIOAutocompleteUICustomization.html ├── CIOErrorView.html ├── CIOHighlightingAttributesProvider.html ├── CIOLogger.html ├── CIOSessionManagerDelegate.html └── SessionManager.html ├── Response Structures.html ├── Result Classes.html ├── Result Request Builders.html ├── Result Request Classes.html ├── Result Request Objects.html ├── Result Request Structures.html ├── Result Structures & Classes.html ├── Structs.html ├── Structs ├── AutocompleteResultCount.html ├── AutocompleteViewModelSection.html ├── CIOABTestCell.html ├── CIOAutocompleteQuery.html ├── CIOAutocompleteResponse.html ├── CIOBrowseFacetOptionsQuery.html ├── CIOBrowseFacetOptionsResponse.html ├── CIOBrowseFacetsQuery.html ├── CIOBrowseFacetsResponse.html ├── CIOBrowseGroupsQuery.html ├── CIOBrowseItemsQuery.html ├── CIOBrowseQuery.html ├── CIOBrowseResponse.html ├── CIOFilterFacet.html ├── CIOFilterFacetOption.html ├── CIOQueryFilters.html ├── CIOQuizImages.html ├── CIOQuizOption.html ├── CIOQuizOptionAttribute.html ├── CIOQuizQuery.html ├── CIOQuizQuestion.html ├── CIOQuizQuestionResponse.html ├── CIOQuizResult.html ├── CIOQuizResultsResponse.html ├── CIORecommendationsPod.html ├── CIORecommendationsQuery.html ├── CIORecommendationsResponse.html ├── CIORecommendationsStrategy.html ├── CIORefinedContent.html ├── CIOResultData.html ├── CIOResultFacet.html ├── CIOSearchQuery.html ├── CIOSearchRedirectInfo.html ├── CIOSearchResponse.html ├── CIOSortOption.html └── ConstructorIOConfig.html ├── Tracking Request Classes.html ├── Typealiases.html ├── badge.svg ├── css ├── highlight.css └── jazzy.css ├── docsets ├── ConstructorAutocomplete.docset │ └── Contents │ │ ├── Info.plist │ │ └── Resources │ │ ├── Documents │ │ ├── Classes.html │ │ ├── Classes │ │ │ ├── AutocompleteResult.html │ │ │ ├── AutocompleteViewModel.html │ │ │ ├── BoldAttributesProvider.html │ │ │ ├── CIOAutocompleteQueryBuilder.html │ │ │ ├── CIOAutocompleteResult.html │ │ │ ├── CIOAutocompleteViewController.html │ │ │ ├── CIOBrowseFacetOptionsQueryBuilder.html │ │ │ ├── CIOBrowseFacetsQueryBuilder.html │ │ │ ├── CIOBrowseGroupsQueryBuilder.html │ │ │ ├── CIOBrowseItemsQueryBuilder.html │ │ │ ├── CIOBrowseQueryBuilder.html │ │ │ ├── CIOCollectionData.html │ │ │ ├── CIOFilterGroup.html │ │ │ ├── CIOGroup.html │ │ │ ├── CIOHighlighter.html │ │ │ ├── CIOPrintLogger.html │ │ │ ├── CIORecommendationsQueryBuilder.html │ │ │ ├── CIOResult.html │ │ │ ├── CIOResultSourceData.html │ │ │ ├── CIOResultSources.html │ │ │ ├── CIOSearchQueryBuilder.html │ │ │ ├── ConstructorIO.html │ │ │ ├── CustomSearchBar.html │ │ │ ├── CustomSearchController.html │ │ │ ├── DefaultSearchItemCell.html │ │ │ ├── EmptyScreenView.html │ │ │ ├── Session.html │ │ │ └── TaskResponse.html │ │ ├── Client.html │ │ ├── Constructor IO Client.html │ │ ├── Enums.html │ │ ├── Enums │ │ │ ├── CIOError.html │ │ │ ├── CIOSearchBarDisplayMode.html │ │ │ └── CIOSortOrder.html │ │ ├── Extensions.html │ │ ├── Extensions │ │ │ └── UISearchBar.html │ │ ├── Other Classes.html │ │ ├── Other Enums.html │ │ ├── Other Protocols.html │ │ ├── Other Structs.html │ │ ├── Protocols.html │ │ ├── Protocols │ │ │ ├── AbstractAutocompleteViewModel.html │ │ │ ├── AutocompleteViewModelDelegate.html │ │ │ ├── CIOAutocompleteCell.html │ │ │ ├── CIOAutocompleteDelegate.html │ │ │ ├── CIOAutocompleteUICustomization.html │ │ │ ├── CIOErrorView.html │ │ │ ├── CIOHighlightingAttributesProvider.html │ │ │ ├── CIOLogger.html │ │ │ ├── CIOSessionManagerDelegate.html │ │ │ └── SessionManager.html │ │ ├── Response Structures.html │ │ ├── Result Classes.html │ │ ├── Result Request Builders.html │ │ ├── Result Request Classes.html │ │ ├── Result Request Objects.html │ │ ├── Result Request Structures.html │ │ ├── Result Structures & Classes.html │ │ ├── Structs.html │ │ ├── Structs │ │ │ ├── AutocompleteResultCount.html │ │ │ ├── AutocompleteViewModelSection.html │ │ │ ├── CIOABTestCell.html │ │ │ ├── CIOAutocompleteQuery.html │ │ │ ├── CIOAutocompleteResponse.html │ │ │ ├── CIOBrowseFacetOptionsQuery.html │ │ │ ├── CIOBrowseFacetOptionsResponse.html │ │ │ ├── CIOBrowseFacetsQuery.html │ │ │ ├── CIOBrowseFacetsResponse.html │ │ │ ├── CIOBrowseGroupsQuery.html │ │ │ ├── CIOBrowseItemsQuery.html │ │ │ ├── CIOBrowseQuery.html │ │ │ ├── CIOBrowseResponse.html │ │ │ ├── CIOFilterFacet.html │ │ │ ├── CIOFilterFacetOption.html │ │ │ ├── CIOQueryFilters.html │ │ │ ├── CIOQuizImages.html │ │ │ ├── CIOQuizOption.html │ │ │ ├── CIOQuizOptionAttribute.html │ │ │ ├── CIOQuizQuery.html │ │ │ ├── CIOQuizQuestion.html │ │ │ ├── CIOQuizQuestionResponse.html │ │ │ ├── CIOQuizResult.html │ │ │ ├── CIOQuizResultsResponse.html │ │ │ ├── CIORecommendationsPod.html │ │ │ ├── CIORecommendationsQuery.html │ │ │ ├── CIORecommendationsResponse.html │ │ │ ├── CIORecommendationsStrategy.html │ │ │ ├── CIORefinedContent.html │ │ │ ├── CIOResultData.html │ │ │ ├── CIOResultFacet.html │ │ │ ├── CIOSearchQuery.html │ │ │ ├── CIOSearchRedirectInfo.html │ │ │ ├── CIOSearchResponse.html │ │ │ ├── CIOSortOption.html │ │ │ └── ConstructorIOConfig.html │ │ ├── Tracking Request Classes.html │ │ ├── Typealiases.html │ │ ├── badge.svg │ │ ├── css │ │ │ ├── highlight.css │ │ │ └── jazzy.css │ │ ├── img │ │ │ ├── carat.png │ │ │ ├── dash.png │ │ │ ├── gh.png │ │ │ └── spinner.gif │ │ ├── index.html │ │ ├── js │ │ │ ├── jazzy.js │ │ │ ├── jazzy.search.js │ │ │ ├── jquery.min.js │ │ │ ├── lunr.min.js │ │ │ └── typeahead.jquery.js │ │ ├── search.json │ │ └── undocumented.json │ │ └── docSet.dsidx └── ConstructorAutocomplete.tgz ├── img ├── carat.png ├── dash.png ├── gh.png └── spinner.gif ├── index.html ├── js ├── jazzy.js ├── jazzy.search.js ├── jquery.min.js ├── lunr.min.js └── typeahead.jquery.js ├── search.json └── undocumented.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | # Maintain dependencies for ruby packages 5 | - package-ecosystem: "bundler" 6 | directory: "/" 7 | schedule: 8 | interval: "daily" 9 | # Disable version updates for ruby dependencies 10 | # This option has no impact on security updates, which have a separate, internal limit of ten open pull requests. 11 | open-pull-requests-limit: 0 12 | reviewers: 13 | - "crgee1" # Chris 14 | - "jjl014" # Jimmy 15 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-alerts-to-slack.yml: -------------------------------------------------------------------------------- 1 | name: 'Check for Dependabot alerts & send them to Slack' 2 | 3 | on: 4 | schedule: 5 | - cron: '30 16 * * *' # every day at 9:30 am PST 6 | workflow_dispatch: # to have the option to run this ad-hoc 7 | 8 | jobs: 9 | main: 10 | uses: Constructor-io/customer-integrations-public-github-workflows/.github/workflows/dependabot-alerts-to-slack.yml@main 11 | secrets: 12 | github-app-id: ${{ vars.DEPENDABOT_ACCESS_APP_ID }} 13 | github-app-private-key: ${{ secrets.DEPENDABOT_ACCESS_PRIVATE_KEY }} 14 | slack-webhook: ${{ secrets.CUSTOMER_INTEGRATIONS_SLACK_WEBHOOK }} 15 | 16 | -------------------------------------------------------------------------------- /.slather.yml: -------------------------------------------------------------------------------- 1 | # .slather.yml 2 | 3 | scheme: ConstructorAutocomplete 4 | workspace: AutocompleteClient.xcworkspace 5 | xcodeproj: AutocompleteClient.xcodeproj -------------------------------------------------------------------------------- /.swiftlint.auto.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - AutocompleteClient 3 | - AutocompleteClientTests 4 | excluded: 5 | - Tests/SwiftLintFrameworkTests/Resources 6 | analyzer_rules: 7 | - unused_import 8 | - unused_private_declaration 9 | disabled_rules: 10 | - line_length 11 | - identifier_name 12 | - number_separator 13 | - unused_closure_parameter 14 | - type_name 15 | opt_in_rules: 16 | - control_statement -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - AutocompleteClient 3 | - AutocompleteClientTests 4 | excluded: 5 | - Tests/SwiftLintFrameworkTests/Resources 6 | analyzer_rules: 7 | - unused_import 8 | - unused_private_declaration 9 | disabled_rules: 10 | - line_length 11 | - identifier_name 12 | - number_separator 13 | - unused_closure_parameter 14 | - type_name 15 | opt_in_rules: 16 | - anyobject_protocol 17 | - array_init 18 | - attributes 19 | - closure_end_indentation 20 | - closure_spacing 21 | - collection_alignment 22 | - contains_over_first_not_nil 23 | - empty_count 24 | - empty_string 25 | - empty_xctest_method 26 | - explicit_init 27 | - extension_access_modifier 28 | - fallthrough 29 | - fatal_error_message 30 | - file_header 31 | - file_name 32 | - first_where 33 | - identical_operands 34 | - joined_default_parameter 35 | - let_var_whitespace 36 | - literal_expression_end_indentation 37 | - lower_acl_than_parent 38 | - nimble_operator 39 | - number_separator 40 | - object_literal 41 | - operator_usage_whitespace 42 | - overridden_super_call 43 | - override_in_extension 44 | - pattern_matching_keywords 45 | - private_action 46 | - private_outlet 47 | - prohibited_interface_builder 48 | - prohibited_super_call 49 | - quick_discouraged_call 50 | - quick_discouraged_focused_test 51 | - quick_discouraged_pending_test 52 | - redundant_nil_coalescing 53 | - redundant_type_annotation 54 | - single_test_class 55 | - sorted_first_last 56 | - sorted_imports 57 | - static_operator 58 | - unavailable_function 59 | - unneeded_parentheses_in_closure_argument 60 | - untyped_error_in_catch 61 | - vertical_parameter_alignment_on_call 62 | - yoda_condition 63 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutocompleteClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutocompleteClient.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AutocompleteClient.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | PreviewsEnabled 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AutocompleteClient.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AutocompleteClient.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AutocompleteClient.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AutocompleteClient/ConstructorAutocomplete-Swift.h: -------------------------------------------------------------------------------- 1 | // 2 | // ConstructorAutocomplete-Swift.h 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AutocompleteClient. 12 | FOUNDATION_EXPORT double AutocompleteClientVersionNumber; 13 | 14 | //! Project version string for AutocompleteClient. 15 | FOUNDATION_EXPORT const unsigned char AutocompleteClientVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Data/TaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaskResponse.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Task response must be constructed through one of the two constructors so it's impossible to have a response 13 | that has no data and no error 14 | */ 15 | public class TaskResponse { 16 | public let data: T? 17 | public let error: E? 18 | 19 | public init(data: T) { 20 | self.data = data 21 | self.error = nil 22 | } 23 | 24 | public init(error: E) { 25 | self.data = nil 26 | self.error = error 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Error/NSError+Errors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSError+Unknown.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | let kConstructorUnknownErrorCode = 0xf 12 | let kConstructorJSONErrorCode = 0xf0 13 | 14 | extension NSError { 15 | class func unknownError() -> NSError { 16 | return NSError(domain: "unknownError", code: kConstructorUnknownErrorCode, userInfo: nil) 17 | } 18 | 19 | class func jsonParseError() -> NSError { 20 | return NSError(domain: "jsonParseError", code: kConstructorJSONErrorCode, userInfo: nil) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Client/NetworkClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkClient.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol NetworkClient { 12 | 13 | func execute(_ request: URLRequest, completionHandler: @escaping (_ response: NetworkResponse) -> Void) 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/AutocompleteTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteTaskResponse.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public class AutocompleteTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/BrowseFacetOptionsTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrowseFacetOptionsTaskResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class BrowseFacetOptionsTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/BrowseFacetsTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrowseFacetsTaskResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class BrowseFacetsTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/BrowseTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchTaskResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class BrowseTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/NetworkResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkResponse.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public class NetworkResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/QuizQuestionTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuizQuestionTaskResponse.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public class QuizQuestionTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/QuizResultsTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuizResultsTaskResponse.swift 3 | // ConstructorAutocomplete 4 | // 5 | // Created by Islam Mouatafa on 11/10/22. 6 | // Copyright © 2022 xd. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class QuizResultsTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/RecommendationsTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RecommendationsTaskResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class RecommendationsTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/SearchTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchTaskResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class SearchTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Network/Response/TrackingTaskResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TrackingTaskResponse.swift 3 | // ConstructorAutocomplete 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class TrackingTaskResponse: TaskResponse {} 12 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Autocomplete/AbstractAutocompleteResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractAutocompleteResponseParser.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol AbstractAutocompleteResponseParser { 12 | 13 | var delegate: ResponseParserDelegate? { get set } 14 | var maxGroups: Int? { get set } 15 | func parse(autocompleteResponseData: Data) throws -> CIOAutocompleteResponse 16 | } 17 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Autocomplete/ResponseParserDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseParserDelegate.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ResponseParserDelegate: AnyObject { 12 | func shouldParseResult(result: CIOResult, inGroup group: CIOGroup?) -> Bool? 13 | func maximumGroupsShownPerResult(result: CIOResult, at index: Int) -> Int 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Browse/AbstractBrowseFacetOptionsResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractBrowseFacetOptionsResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AbstractBrowseFacetOptionsResponseParser { 12 | 13 | func parse(browseFacetOptionsResponseData: Data) throws -> CIOBrowseFacetOptionsResponse 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Browse/AbstractBrowseFacetsResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractBrowseFacetsResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AbstractBrowseFacetsResponseParser { 12 | 13 | func parse(browseFacetsResponseData: Data) throws -> CIOBrowseFacetsResponse 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Browse/AbstractBrowseResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractBrowseResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AbstractBrowseResponseParser { 12 | 13 | func parse(browseResponseData: Data) throws -> CIOBrowseResponse 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Browse/BrowseFacetOptionsResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrowseFacetOptionsResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | class BrowseFacetOptionsResponseParser: AbstractBrowseFacetOptionsResponseParser { 12 | func parse(browseFacetOptionsResponseData: Data) throws -> CIOBrowseFacetOptionsResponse { 13 | 14 | do { 15 | let json = try JSONSerialization.jsonObject(with: browseFacetOptionsResponseData) as? JSONObject 16 | 17 | guard let response = json?["response"] as? JSONObject else { 18 | throw CIOError(errorType: .invalidResponse) 19 | } 20 | 21 | let facetsObj: [JSONObject]? = response["facets"] as? [JSONObject] 22 | 23 | let facets: [CIOFilterFacet] = (facetsObj)?.compactMap { obj in return CIOFilterFacet(json: obj) } ?? [] 24 | let resultID = json?["result_id"] as? String ?? "" 25 | 26 | return CIOBrowseFacetOptionsResponse( 27 | facets: facets, 28 | resultID: resultID 29 | ) 30 | } catch { 31 | throw CIOError(errorType: .invalidResponse) 32 | } 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Browse/BrowseFacetsResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrowseFacetsResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | class BrowseFacetsResponseParser: AbstractBrowseFacetsResponseParser { 12 | func parse(browseFacetsResponseData: Data) throws -> CIOBrowseFacetsResponse { 13 | 14 | do { 15 | let json = try JSONSerialization.jsonObject(with: browseFacetsResponseData) as? JSONObject 16 | 17 | guard let response = json?["response"] as? JSONObject else { 18 | throw CIOError(errorType: .invalidResponse) 19 | } 20 | 21 | let facetsObj: [JSONObject]? = response["facets"] as? [JSONObject] 22 | 23 | let facets: [CIOFilterFacet] = (facetsObj)?.compactMap { obj in return CIOFilterFacet(json: obj) } ?? [] 24 | let totalNumResults = response["total_num_results"] as? Int ?? 0 25 | let resultID = json?["result_id"] as? String ?? "" 26 | 27 | return CIOBrowseFacetsResponse( 28 | facets: facets, 29 | totalNumResults: totalNumResults, 30 | resultID: resultID 31 | ) 32 | } catch { 33 | throw CIOError(errorType: .invalidResponse) 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Quizzes/AbstractQuizQuestionResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractQuizQuestionResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AbstractQuizQuestionResponseParser { 12 | 13 | func parse(quizQuestionResponseData: Data) throws -> CIOQuizQuestionResponse 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Quizzes/AbstractQuizResultsResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractQuizResultsResponseParser.swift 3 | // ConstructorAutocomplete 4 | // 5 | // Created by Islam Mouatafa on 11/11/22. 6 | // Copyright © 2022 xd. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AbstractQuizResultsResponseParser { 12 | 13 | func parse(quizResultsResponseData: Data) throws -> CIOQuizResultsResponse 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Quizzes/QuizQuestionResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuizQuestionResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | class QuizQuestionResponseParser: AbstractQuizQuestionResponseParser { 12 | func parse(quizQuestionResponseData: Data) throws -> CIOQuizQuestionResponse { 13 | 14 | do { 15 | let json = try JSONSerialization.jsonObject(with: quizQuestionResponseData) as? JSONObject 16 | let quizVersionID = json?["quiz_version_id"] as? String ?? "" 17 | let quizID = json?["quiz_id"] as? String ?? "" 18 | let quizSessionID = json?["quiz_session_id"] as? String ?? "" 19 | let nextQuestion = CIOQuizQuestion(json: json?["next_question"] as? JSONObject ?? [:]) 20 | 21 | return CIOQuizQuestionResponse( 22 | nextQuestion: nextQuestion!, 23 | quizVersionID: quizVersionID, 24 | quizSessionID: quizSessionID, 25 | quizID: quizID 26 | ) 27 | } catch { 28 | throw CIOError(errorType: .invalidResponse) 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Recommendations/AbstractRecommendationsResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractRecommendationsResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AbstractRecommendationsResponseParser { 12 | 13 | func parse(recommendationsResponseData: Data) throws -> CIORecommendationsResponse 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/API/Parser/Search/AbstractSearchResponseParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractSearchResponseParser.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol AbstractSearchResponseParser { 12 | 13 | func parse(searchResponseData: Data) throws -> CIOSearchResponse 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Config/AutocompleteResultCount.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteResultCount.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the result count 13 | */ 14 | public struct AutocompleteResultCount { 15 | /** 16 | The total number of results to request for 17 | */ 18 | public let numResults: Int? 19 | 20 | /** 21 | The number of results to request for per section 22 | */ 23 | public let numResultsForSection: [String: Int]? 24 | 25 | /** 26 | Create a result count object with a set number of results to be returned overall 27 | 28 | - Parameters: 29 | - numResults: Total number of results to be returned 30 | 31 | ### Usage Example: ### 32 | ``` 33 | let resultCount = AutocompleteResultCount(numResults: 10) 34 | ``` 35 | */ 36 | public init(numResults: Int) { 37 | self.numResults = numResults 38 | self.numResultsForSection = nil 39 | } 40 | 41 | /** 42 | Create a result count object with a set number of results to be returned overall 43 | 44 | - Parameters: 45 | - numResultsForSection: Number of results to be returned per section 46 | 47 | ### Usage Example: ### 48 | ``` 49 | let resultCount = AutocompleteResultCount(numResultsForSection: ["Search Suggestions": 3, "Products": 4]) 50 | ``` 51 | */ 52 | public init(numResultsForSection: [String: Int]) { 53 | self.numResultsForSection = numResultsForSection 54 | self.numResults = nil 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logging/CIOLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOLogger.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol CIOLogger { 12 | func log(_ message: String) 13 | } 14 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logging/CIOPrintLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOPrintLogger.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public class CIOPrintLogger: CIOLogger { 12 | public func log(_ message: String) { 13 | #if DEBUG 14 | print(message) 15 | #endif 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/ABTesting/CIOABTestCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOABTestCell.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the AB test cell 13 | */ 14 | public struct CIOABTestCell { 15 | /** 16 | The name of the test cell 17 | */ 18 | let key: String 19 | 20 | /** 21 | The test cell value 22 | */ 23 | let value: String 24 | 25 | /** 26 | Create a AB test cell object 27 | 28 | - Parameters: 29 | - key: The name of the test cell 30 | - value: The test cell value 31 | 32 | ``` 33 | ### Usage Example: ### 34 | let testCell = CIOABTestCell(key: "search", value: "control") 35 | ``` 36 | */ 37 | public init(key: String, value: String) { 38 | self.key = key 39 | self.value = value 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/ClientID/ClientIDGenerator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClientIDGenerator.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class ClientIDGenerator: IDGenerator { 13 | 14 | init() {} 15 | 16 | func generateID() -> String? { 17 | return UIDevice.current.identifierForVendor?.uuidString 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/ClientID/IDGenerator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserIDGenerator.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol IDGenerator { 12 | func generateID() -> String? 13 | } 14 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/ClientID/Persistence/CIOClientIdLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOClientIdLoader.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | struct CIOClientIdLoader: ClientIdLoader { 12 | 13 | init() {} 14 | 15 | func loadClientId() -> String? { 16 | if let clientId = UserDefaults.standard.object(forKey: Constants.Session.clientId) as? String { 17 | return clientId 18 | } else if let clientId = DependencyContainer.sharedInstance.clientIDGenerator().generateID() { 19 | saveClientId(clientId) 20 | return clientId 21 | } else { 22 | let uuid = NSUUID().uuidString 23 | saveClientId(uuid) 24 | return uuid 25 | } 26 | } 27 | 28 | func saveClientId(_ clientId: String) { 29 | UserDefaults.standard.set(clientId, forKey: Constants.Session.clientId) 30 | } 31 | 32 | func clearClientId() { 33 | UserDefaults.standard.removeObject(forKey: Constants.Session.clientId) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/ClientID/Persistence/ClientIdLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClientIdLoader.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol ClientIdLoader { 12 | 13 | func loadClientId() -> String? 14 | func saveClientId(_ clientId: String) 15 | 16 | func clearClientId() 17 | } 18 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Highlighting/Attributes/BoldAttributesProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BoldAttributesProvider.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class BoldAttributesProvider: CIOHighlightingAttributesProvider { 12 | 13 | public var fontNormal: UIFont 14 | public var fontBold: UIFont 15 | 16 | public var colorNormal: UIColor 17 | public var colorBold: UIColor 18 | 19 | public init(fontNormal: UIFont, fontBold: UIFont, colorNormal: UIColor, colorBold: UIColor) { 20 | self.colorNormal = colorNormal 21 | self.colorBold = colorBold 22 | self.fontNormal = fontNormal 23 | self.fontBold = fontBold 24 | } 25 | 26 | public func defaultSubstringAttributes() -> [NSAttributedString.Key: Any] { 27 | return [NSAttributedString.Key.font: self.fontBold, 28 | NSAttributedString.Key.foregroundColor: self.colorBold] 29 | } 30 | 31 | public func highlightedSubstringAttributes() -> [NSAttributedString.Key: Any] { 32 | return [NSAttributedString.Key.font: self.fontNormal, 33 | NSAttributedString.Key.foregroundColor: self.colorNormal] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Highlighting/Attributes/CIOHighlightingAttributesProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOHighlightingAttributesProvider.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Provides higlighting attributes. 13 | */ 14 | public protocol CIOHighlightingAttributesProvider { 15 | /** 16 | Method called by the CIOHiglighter to get highlighting attributes for parts of the string that aren't matched in the search term. 17 | 18 | - returns: NSAttributeString attributes for unmatched parts of the search term. 19 | */ 20 | func defaultSubstringAttributes() -> [NSAttributedString.Key: Any] 21 | 22 | /** 23 | Method called by the CIOHiglighter to get highlighting attributes for parts of the string that are matched in the search term. 24 | 25 | - returns: NSAttributeString attributes for matched parts of the search term. 26 | */ 27 | func highlightedSubstringAttributes() -> [NSAttributedString.Key: Any] 28 | } 29 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Query/CIOQueryFilters.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchFilters.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias Filter = (key: String, value: String) 12 | 13 | public struct CIOQueryFilters { 14 | public let groupFilter: String? 15 | public let facetFilters: [Filter]? 16 | 17 | public init(groupFilter: String?, facetFilters: [Filter]?) { 18 | self.groupFilter = groupFilter 19 | self.facetFilters = facetFilters 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Query/CIOQueryFmtOptions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOQueryFmtOptions.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias FmtOption = (key: String, value: String) 12 | 13 | public struct CIOQueryFmtOptions { 14 | public let fmtOptions: [FmtOption]? 15 | 16 | public init(fmtOptions: [FmtOption]?) { 17 | self.fmtOptions = fmtOptions 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/Builder/CIOBrowseFacetOptionsQueryBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOBrowseFacetOptionsQueryBuilder.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Request builder for creating an browse facet options query. 13 | */ 14 | public class CIOBrowseFacetOptionsQueryBuilder { 15 | 16 | /** 17 | The name of the facet whose options to return 18 | */ 19 | var facetName: String 20 | 21 | /** 22 | Whether or not to return hidden facets 23 | */ 24 | var showHiddenFacets: Bool? 25 | 26 | /** 27 | Create a Browse facet options request query builder 28 | */ 29 | public init(facetName: String) { 30 | self.facetName = facetName 31 | } 32 | 33 | /** 34 | Add a bool indicating whether or not to return hidden facets 35 | */ 36 | public func setShowHiddenFacets(_ showHiddenFacets: Bool) -> CIOBrowseFacetOptionsQueryBuilder { 37 | self.showHiddenFacets = showHiddenFacets 38 | return self 39 | } 40 | 41 | /** 42 | Build the request object set all of the provided data 43 | 44 | ### Usage Example: ### 45 | ``` 46 | let query = CIOBrowseFacetOptionsQueryBuilder(facetName: "price") 47 | .setShowHiddenFacets(true) 48 | .build() 49 | 50 | constructor.browseFacetOptions(forQuery: query, completionHandler: { ... }) 51 | ``` 52 | */ 53 | public func build() -> CIOBrowseFacetOptionsQuery { 54 | return CIOBrowseFacetOptionsQuery(facetName: facetName, showHiddenFacets: showHiddenFacets) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIOBrowseFacetOptionsQuery.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOBrowseFacetOptionsQuery.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the necessary and additional parameters required to execute a browse facet options query. 13 | */ 14 | public struct CIOBrowseFacetOptionsQuery: CIORequestData { 15 | /** 16 | Name of the facet whose options to return 17 | */ 18 | public let facetName: String 19 | 20 | /** 21 | Whether or not to return hidden facets 22 | */ 23 | public let showHiddenFacets: Bool? 24 | 25 | func url(with baseURL: String) -> String { 26 | return String(format: Constants.BrowseFacetOptionsQuery.format, baseURL) 27 | } 28 | 29 | /** 30 | Create a Browse facet options request query object 31 | 32 | - Parameters: 33 | - facetName: Name of the facet whose options to return 34 | - showHiddenFacets: Whether or not to return hidden facets 35 | 36 | ### Usage Example: ### 37 | ``` 38 | let browseFacetsQuery = CIOBrowseFacetOptionsQuery(facetName: "price", showHiddenFacets: true) 39 | ``` 40 | */ 41 | public init(facetName: String, showHiddenFacets: Bool? = nil) { 42 | self.facetName = facetName 43 | self.showHiddenFacets = showHiddenFacets 44 | } 45 | 46 | func decorateRequest(requestBuilder: RequestBuilder) { 47 | requestBuilder.set(facetName: self.facetName) 48 | 49 | if self.showHiddenFacets != nil { 50 | requestBuilder.set(showHiddenFacets: self.showHiddenFacets!) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIOGroupsSortOption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOGroupsSortOption.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a group sort option 13 | */ 14 | public struct CIOGroupsSortOption { 15 | /** 16 | The sort method ("relevance", "value", or "num_matches") 17 | */ 18 | public let sortBy: CIOGroupsSortBy 19 | 20 | /** 21 | The sort order (i.e. "ascending" or "descending") 22 | */ 23 | public let sortOrder: CIOGroupsSortOrder 24 | 25 | /** 26 | Create a groups sort option 27 | 28 | - parameters 29 | - sortBy: The sort method ("relevance", "value", or "num_matches") 30 | - sortOrder: The sort order (i.e. "ascending" or "descending" 31 | */ 32 | public init(sortBy: CIOGroupsSortBy, sortOrder: CIOGroupsSortOrder) { 33 | self.sortBy = sortBy 34 | self.sortOrder = sortOrder 35 | } 36 | 37 | public enum CIOGroupsSortBy: String { 38 | case relevance 39 | case value 40 | case num_matches 41 | } 42 | 43 | public enum CIOGroupsSortOrder: String { 44 | case ascending 45 | case descending 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIOItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOItem.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public struct CIOItem { 12 | var customerID: String 13 | var variationID: String? 14 | var quantity: Int? 15 | 16 | public init(customerID: String, variationID: String? = nil, quantity: Int? = nil) { 17 | self.customerID = customerID 18 | self.variationID = variationID 19 | self.quantity = quantity 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIORequestData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIORequestData.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol CIORequestData { 12 | 13 | func decorateRequest(requestBuilder: RequestBuilder) 14 | 15 | func url(with baseURL: String) -> String 16 | 17 | func urlWithFormat(baseURL: String, format: String) -> String 18 | 19 | func queryItems(baseItems: [URLQueryItem]) -> [URLQueryItem] 20 | 21 | func httpMethod() -> String 22 | 23 | func httpBody(baseParams: [String: Any]) -> Data? 24 | } 25 | 26 | extension CIORequestData { 27 | // default httpMethod is GET 28 | func httpMethod() -> String { 29 | return "GET" 30 | } 31 | 32 | // default body is null 33 | func httpBody(baseParams: [String: Any]) -> Data? { 34 | return nil 35 | } 36 | 37 | // default query items is all of them 38 | func queryItems(baseItems: [URLQueryItem]) -> [URLQueryItem] { 39 | return baseItems 40 | } 41 | 42 | // default to empty string 43 | func urlWithFormat(baseURL: String, format: String) -> String { 44 | return "" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIOTrackInputFocusData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOTrackInputFocusData.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the parameters that must/can be set set in order to track search bar focus 13 | */ 14 | struct CIOTrackInputFocusData: CIORequestData { 15 | let searchTerm: String? 16 | 17 | func url(with baseURL: String) -> String { 18 | return String(format: Constants.TrackInputFocus.format, baseURL) 19 | } 20 | 21 | init(searchTerm: String?) { 22 | self.searchTerm = searchTerm 23 | } 24 | 25 | func decorateRequest(requestBuilder: RequestBuilder) { 26 | if let term = self.searchTerm { 27 | requestBuilder.set(searchTerm: term) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIOTrackSearchResultClickData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOTrackSearchResultClickData.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the parameters that must/can be set set in order to track search result click 13 | */ 14 | struct CIOTrackSearchResultClickData: CIORequestData { 15 | let searchTerm: String 16 | let itemName: String 17 | let customerID: String 18 | var sectionName: String? 19 | let resultID: String? 20 | let variationID: String? 21 | 22 | func url(with baseURL: String) -> String { 23 | return String(format: Constants.TrackSearchResultClick.format, baseURL, self.searchTerm.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!) 24 | } 25 | 26 | init(searchTerm: String, itemName: String, customerID: String, sectionName: String? = nil, resultID: String? = nil, variationID: String? = nil) { 27 | self.searchTerm = searchTerm 28 | self.itemName = itemName 29 | self.customerID = customerID 30 | self.sectionName = sectionName 31 | self.resultID = resultID 32 | self.variationID = variationID 33 | } 34 | 35 | func decorateRequest(requestBuilder: RequestBuilder) { 36 | requestBuilder.set(name: self.itemName) 37 | requestBuilder.set(customerID: self.customerID) 38 | requestBuilder.set(autocompleteSection: self.sectionName) 39 | requestBuilder.set(resultID: self.resultID) 40 | requestBuilder.set(variationID: self.variationID) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIOTrackSearchSubmitData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOTrackSearchSubmitData.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the parameters that must/can be set in order to track a search submission 13 | */ 14 | struct CIOTrackSearchSubmitData: CIORequestData { 15 | 16 | let searchTerm: String 17 | let originalQuery: String 18 | let group: CIOGroup? 19 | 20 | func url(with baseURL: String) -> String { 21 | return String(format: Constants.TrackSearchSubmit.format, baseURL, self.searchTerm.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!) 22 | } 23 | 24 | init(searchTerm: String, originalQuery: String, group: CIOGroup? = nil) { 25 | self.searchTerm = searchTerm 26 | self.originalQuery = originalQuery 27 | self.group = group 28 | } 29 | 30 | func decorateRequest(requestBuilder: RequestBuilder) { 31 | requestBuilder.set(originalQuery: self.originalQuery) 32 | if let group = self.group { 33 | requestBuilder.set(groupName: group.displayName) 34 | requestBuilder.set(groupID: group.groupID) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Request/CIOTrackSessionStartData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOTrackSessionStartData.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the parameters that must/can be set set in order to track session start 13 | */ 14 | struct CIOTrackSessionStartData: CIORequestData { 15 | let session: Int 16 | 17 | func url(with baseURL: String) -> String { 18 | return String(format: Constants.TrackSessionStart.format, baseURL) 19 | } 20 | 21 | init(session: Int) { 22 | self.session = session 23 | } 24 | 25 | func decorateRequest(requestBuilder: RequestBuilder) { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOAutocompleteResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOAutocompleteResult.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | import Foundation 9 | 10 | /** 11 | Defines an autocomplete item in the list. Since you can search for a term in a group, this class holds 12 | both the result and the group to search in. 13 | */ 14 | 15 | @objc 16 | public class CIOAutocompleteResult: NSObject { 17 | /** 18 | Result returned for the query 19 | */ 20 | public let result: CIOResult 21 | 22 | /** 23 | Group (or category) the result belongs to 24 | */ 25 | public let group: CIOGroup? 26 | 27 | /** 28 | Create a autocomplete result 29 | 30 | - Parameters: 31 | - result: Result info 32 | - group: Group info 33 | */ 34 | public init(result: CIOResult, group: CIOGroup? = nil) { 35 | self.result = result 36 | self.group = group 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOCollectionData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOCollectionData.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | import Foundation 9 | 10 | /** 11 | Struct encapsulating a collection 12 | */ 13 | public class CIOCollectionData: NSObject { 14 | /** 15 | Id of the collection 16 | */ 17 | public let id: String 18 | 19 | /** 20 | Display name of the collection 21 | */ 22 | public let display_name: String 23 | 24 | /** 25 | Additional metadata for the collection 26 | */ 27 | public let data: [String: Any] 28 | 29 | /** 30 | Create a collection object 31 | 32 | - Parameters: 33 | - json: JSON data from server reponse 34 | */ 35 | init?(json: JSONObject?) { 36 | guard let json = json, let id = json["id"] as? String, let display_name = json["display_name"] as? String else { 37 | return nil 38 | } 39 | 40 | let data = json["data"] as? [String: Any] ?? [:] 41 | 42 | self.id = id 43 | self.display_name = display_name 44 | self.data = data 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOGroup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOGroup.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a group 13 | */ 14 | @objc 15 | public class CIOGroup: NSObject { 16 | /** 17 | Display name of the group (or category) 18 | */ 19 | public let displayName: String 20 | 21 | /** 22 | Group ID 23 | */ 24 | public let groupID: String 25 | 26 | /** 27 | The full path of the group hierarchy 28 | */ 29 | public let path: String? 30 | 31 | /** 32 | Create a group 33 | 34 | - Parameters: 35 | - displayName: Display nam eof the group 36 | - groupID: Group ID 37 | - path: The full path of the group hierarchy 38 | */ 39 | public init(displayName: String, groupID: String, path: String?) { 40 | self.displayName = displayName 41 | self.groupID = groupID 42 | self.path = path 43 | } 44 | 45 | /** 46 | Create a group (from JSON) 47 | 48 | - Parameters: 49 | - json: JSON data from the server response 50 | */ 51 | init?(json: JSONObject) { 52 | guard let name = json["display_name"] as? String else { return nil } 53 | guard let groupID = json["group_id"] as? String else { return nil } 54 | 55 | self.displayName = name 56 | self.groupID = groupID 57 | self.path = json["path"] as? String 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOQuizImages.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOQuestionImages.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a question images 13 | */ 14 | public struct CIOQuizImages { 15 | /** 16 | Primary image URL 17 | */ 18 | public let primaryUrl: String? 19 | 20 | /** 21 | Primary image alternative text 22 | */ 23 | public let primaryAlt: String? 24 | 25 | /** 26 | Secondary image URL 27 | */ 28 | public let secondaryUrl: String? 29 | 30 | /** 31 | Secondary image alternative text 32 | */ 33 | public let secondaryAlt: String? 34 | } 35 | 36 | /** 37 | Define a question images 38 | */ 39 | public extension CIOQuizImages { 40 | /** 41 | Create a question images 42 | 43 | - Parameters: 44 | - json: JSON data from the server response 45 | */ 46 | init?(json: JSONObject) { 47 | if let primaryUrl = json["primary_url"] as? String { self.primaryUrl = primaryUrl } else { self.primaryUrl = nil } 48 | if let primaryAlt = json["primary_alt"] as? String { self.primaryAlt = primaryAlt } else { self.primaryAlt = nil } 49 | if let secondaryUrl = json["secondary_url"] as? String { self.secondaryUrl = secondaryUrl } else { self.secondaryUrl = nil } 50 | if let secondaryAlt = json["secondary_alt"] as? String { self.secondaryAlt = secondaryAlt } else { self.secondaryAlt = nil } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOQuizOption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOQuizOption.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a quiz option 13 | */ 14 | public struct CIOQuizOption { 15 | /** 16 | The id of the option 17 | */ 18 | public let id: Int 19 | 20 | /** 21 | The value of the option 22 | */ 23 | public let value: String 24 | 25 | /** 26 | The attribute associated with the option 27 | */ 28 | public let attribute: CIOQuizOptionAttribute? 29 | 30 | /** 31 | The images associated with the option 32 | */ 33 | public let images: CIOQuizImages? 34 | } 35 | 36 | /** 37 | Define a quiz option 38 | */ 39 | public extension CIOQuizOption { 40 | /** 41 | Create a quiz option 42 | 43 | - Parameters: 44 | - json: JSON data from the server response 45 | */ 46 | init?(json: JSONObject) { 47 | guard let id = json["id"] as? Int else { return nil } 48 | guard let value = json["value"] as? String else { return nil } 49 | 50 | if let attribute = json["attribute"] as? JSONObject { 51 | self.attribute = CIOQuizOptionAttribute(json: attribute) 52 | } else { 53 | self.attribute = CIOQuizOptionAttribute(json: [String: Any]()) 54 | } 55 | 56 | if let images = json["images"] as? JSONObject { 57 | self.images = CIOQuizImages(json: images) 58 | } else { 59 | self.images = CIOQuizImages(json: [String: Any]()) 60 | } 61 | 62 | self.id = id 63 | self.value = value 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOQuizOptionAttribute.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOQuizOptionAttribute.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a quiz option attribute 13 | */ 14 | public struct CIOQuizOptionAttribute { 15 | /** 16 | Quiz option attribute name 17 | */ 18 | public let name: String 19 | 20 | /** 21 | Quiz option attribute value 22 | */ 23 | public let value: String 24 | } 25 | 26 | /** 27 | Define a quiz option attribute 28 | */ 29 | public extension CIOQuizOptionAttribute { 30 | /** 31 | Create a quiz option attribute object 32 | 33 | - Parameters: 34 | - json: JSON data from the server response 35 | */ 36 | init?(json: JSONObject) { 37 | guard let name = json["name"] as? String else { return nil } 38 | guard let value = json["value"] as? String else { return nil } 39 | 40 | self.name = name 41 | self.value = value 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOQuizResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOQuizResultsData.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a result data object with additional information about the result 13 | */ 14 | public struct CIOQuizResult { 15 | /** 16 | Filter Expressions 17 | */ 18 | public let filterExpressions: [String: Any] 19 | 20 | /** 21 | Results Url 22 | */ 23 | public let resultsUrl: String 24 | } 25 | 26 | public extension CIOQuizResult { 27 | /** 28 | Create a result data object 29 | - Parameters: 30 | - json: JSON data from the server response 31 | */ 32 | init?(json: JSONObject) { 33 | let filterExpressions = json["filter_expression"] as? [String: Any] ?? [:] 34 | let resultsUrl = json["results_url"] as? String ?? "" 35 | 36 | self.filterExpressions = filterExpressions 37 | self.resultsUrl = resultsUrl 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIORecommendationsPod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIORecommendationsPod.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a recommendations pod 13 | */ 14 | public struct CIORecommendationsPod { 15 | public let displayName: String 16 | public let id: String 17 | } 18 | 19 | /** 20 | Define a recommendations opd 21 | */ 22 | public extension CIORecommendationsPod { 23 | /** 24 | Create a recommendations pod 25 | 26 | - Parameters: 27 | - json: JSON data from the server response 28 | */ 29 | init?(json: JSONObject) { 30 | guard let displayName = json["display_name"] as? String else { return nil } 31 | guard let id = json["id"] as? String else { return nil } 32 | 33 | self.displayName = displayName 34 | self.id = id 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIORecommendationsStrategy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIORecommendationsStrategy.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the recommendations strategy 13 | */ 14 | public struct CIORecommendationsStrategy { 15 | /** 16 | The id of the strategy 17 | */ 18 | public let id: String 19 | } 20 | 21 | public extension CIORecommendationsStrategy { 22 | 23 | /** 24 | Create a recommendations strategy object 25 | 26 | - Parameters: 27 | - json: JSON data from the server response 28 | */ 29 | init?(json: JSONObject) { 30 | let id = json["id"] as? String ?? "" 31 | 32 | self.id = id 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIORefinedContent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIORefinedContent.swift 3 | // ConstructorAutocomplete 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a refined content with associated metadata 13 | */ 14 | public struct CIORefinedContent { 15 | /** 16 | Refine dcontent data 17 | */ 18 | public let data: [String: Any] 19 | 20 | /** 21 | Create a refined content object 22 | 23 | - Parameters: 24 | - json: JSON data from server reponse 25 | */ 26 | public init?(json: JSONObject) { 27 | guard let data = json["data"] as? [String: Any] else { return nil } 28 | 29 | self.data = data 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOResultFacet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOResultFacet.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a result facet 13 | */ 14 | public struct CIOResultFacet { 15 | /** 16 | The name of the facet 17 | */ 18 | public let name: String 19 | 20 | /** 21 | List of facet option values 22 | */ 23 | public let values: [String] 24 | 25 | /** 26 | Create a result facet 27 | 28 | - Parameters: 29 | - json: JSON data from the server response 30 | */ 31 | public init?(json: JSONObject) { 32 | guard let name = json["name"] as? String else { return nil } 33 | 34 | self.name = name 35 | self.values = json["values"] as? [String] ?? [] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOResultSourceData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOResultSourcesData.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | import Foundation 9 | 10 | /** 11 | Struct encapsulating a result source data 12 | */ 13 | public class CIOResultSourceData: NSObject { 14 | /** 15 | Number of results matching 16 | */ 17 | public let count: Int 18 | 19 | /** 20 | Create a result source object 21 | 22 | - Parameters: 23 | - json: JSON data from server reponse 24 | */ 25 | init?(json: JSONObject?) { 26 | guard let json = json, let count = json["count"] as? Int else { 27 | return nil 28 | } 29 | 30 | self.count = count 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOResultSources.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOResultSources.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | import Foundation 9 | 10 | /** 11 | Struct encapsulating a result source 12 | */ 13 | public class CIOResultSources: NSObject { 14 | /** 15 | Number of token match results 16 | */ 17 | public let tokenMatch: CIOResultSourceData 18 | 19 | /** 20 | Number of embedding match results 21 | */ 22 | public let embeddingsMatch: CIOResultSourceData 23 | 24 | /** 25 | Create a result sources object 26 | 27 | - Parameters: 28 | - json: JSON data from server reponse 29 | */ 30 | init?(json: JSONObject?) { 31 | guard let json = json, 32 | let tokenMatchJson = json["token_match"] as? JSONObject, 33 | let embeddingsMatchJson = json["embeddings_match"] as? JSONObject, 34 | let tokenMatchData = CIOResultSourceData(json: tokenMatchJson), 35 | let embeddingsMatchData = CIOResultSourceData(json: embeddingsMatchJson) else { 36 | return nil 37 | } 38 | 39 | self.tokenMatch = tokenMatchData 40 | self.embeddingsMatch = embeddingsMatchData 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOSearchRedirectInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOSearchRedirectInfo.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating the Search redirect info 13 | */ 14 | public struct CIOSearchRedirectInfo { 15 | /** 16 | The redirect URL 17 | */ 18 | public let url: String 19 | 20 | /** 21 | Match ID 22 | */ 23 | public let matchID: Int 24 | 25 | /** 26 | Rule ID 27 | */ 28 | public let ruleID: Int 29 | } 30 | 31 | public extension CIOSearchRedirectInfo { 32 | /** 33 | Create a Search redirect info object 34 | 35 | - Parameters: 36 | - object: JSON Object 37 | */ 38 | init?(object: JSONObject?) { 39 | guard let json = object else { return nil } 40 | guard let data = json["data"] as? JSONObject else { return nil } 41 | guard let url = data["url"] as? String else { return nil } 42 | guard let matchID = data["match_id"] as? Int else { return nil } 43 | guard let ruleID = data["rule_id"] as? Int else { return nil } 44 | 45 | self.url = url 46 | self.matchID = matchID 47 | self.ruleID = ruleID 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/CIOSortOption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SortOption.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct encapsulating a sort option 13 | */ 14 | public struct CIOSortOption { 15 | /** 16 | Display name of the sort option 17 | */ 18 | public let displayName: String 19 | 20 | /** 21 | The field to sort by 22 | */ 23 | public let sortBy: String 24 | 25 | /** 26 | The sort order (i.e. "ascending" or "descending") 27 | */ 28 | public let sortOrder: CIOSortOrder 29 | 30 | /** 31 | The status of the sort option (i.e. "selected") 32 | */ 33 | public let status: String 34 | } 35 | 36 | public extension CIOSortOption { 37 | /** 38 | Create a sort option 39 | 40 | - parameters 41 | - json: JSON data from the server response 42 | */ 43 | init?(json: JSONObject) { 44 | guard let displayName = json["display_name"] as? String else { return nil } 45 | guard let sortOrderStr = json["sort_order"] as? String else { return nil } 46 | guard let sortOrder = CIOSortOrder(rawValue: sortOrderStr) else { return nil } 47 | guard let sortBy = json["sort_by"] as? String else { return nil } 48 | guard let status = json["status"] as? String else { return nil } 49 | 50 | self.displayName = displayName 51 | self.sortBy = sortBy 52 | self.sortOrder = sortOrder 53 | self.status = status 54 | } 55 | } 56 | 57 | public enum CIOSortOrder: String { 58 | case ascending 59 | case descending 60 | } 61 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/Responses/CIOAutocompleteResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOAutocompleteResponse.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias JSONObject = [String: Any] 12 | 13 | /** 14 | Struct representing the autocomplete data response from the server. 15 | */ 16 | public struct CIOAutocompleteResponse { 17 | /** 18 | List of results broken down by sections 19 | */ 20 | public let sections: [String: [CIOAutocompleteResult]] 21 | 22 | /** 23 | Additional information about the request and result ID 24 | */ 25 | public let json: JSONObject 26 | 27 | /** 28 | Request object used to retrieve the Autocomplete Response 29 | */ 30 | public var request: JSONObject 31 | 32 | public init(sections: [String: [CIOAutocompleteResult]], json: JSONObject, request: JSONObject = [:]) { 33 | self.sections = sections 34 | self.json = json 35 | self.request = request 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/Responses/CIOBrowseFacetOptionsResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOBrowseFacetOptionsResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct representing the browse facet options data response from the server. 13 | */ 14 | public struct CIOBrowseFacetOptionsResponse { 15 | /** 16 | List of facets returned 17 | */ 18 | public let facets: [CIOFilterFacet] 19 | 20 | /** 21 | Result ID of the result set returned 22 | */ 23 | public let resultID: String 24 | } 25 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/Responses/CIOBrowseFacetsResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOBrowseFacetsResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct representing the browse facets data response from the server. 13 | */ 14 | public struct CIOBrowseFacetsResponse { 15 | /** 16 | List of facets returned 17 | */ 18 | public let facets: [CIOFilterFacet] 19 | 20 | /** 21 | Total number of results for the query 22 | */ 23 | public let totalNumResults: Int 24 | 25 | /** 26 | Result ID of the result set returned 27 | */ 28 | public let resultID: String 29 | } 30 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/Responses/CIOBrowseResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOBrowseResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct representing the browse data response from the server. 13 | */ 14 | public struct CIOBrowseResponse { 15 | /** 16 | List of facets returned for the result set 17 | */ 18 | public let facets: [CIOFilterFacet] 19 | 20 | /** 21 | List of groups (categories) returned for the result set 22 | */ 23 | public let groups: [CIOFilterGroup] 24 | 25 | /** 26 | List of results returned for the browse query 27 | */ 28 | public let results: [CIOResult] 29 | 30 | /** 31 | List of sorting options 32 | */ 33 | public let sortOptions: [CIOSortOption] 34 | 35 | /** 36 | Total number of results for the query 37 | */ 38 | public let totalNumResults: Int 39 | 40 | /** 41 | Result ID of the result set returned 42 | */ 43 | public let resultID: String 44 | 45 | /** 46 | Collection of the result if browsing collection_id 47 | */ 48 | public let collection: CIOCollectionData? 49 | 50 | /** 51 | A list of refined content 52 | */ 53 | public let refinedContent: [CIORefinedContent] 54 | 55 | /** 56 | Sources of the result set 57 | */ 58 | public let resultSources: CIOResultSources? 59 | 60 | /** 61 | Request object used to retrieve the Browse Response 62 | */ 63 | public var request: JSONObject 64 | } 65 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/Responses/CIOQuizQuestionResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOQuizQuestionResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct representing the quiz question response from the server. 13 | */ 14 | public struct CIOQuizQuestionResponse { 15 | /** 16 | Next question in the quiz 17 | */ 18 | public let nextQuestion: CIOQuizQuestion 19 | 20 | /** 21 | Unique quiz_version_id for the quiz. 22 | The quiz version id will be returned with the first request and it should be passed with subsequent requests. 23 | More information can be found: https://docs.constructor.com/reference/configuration-quizzes 24 | */ 25 | public let quizVersionID: String 26 | 27 | /** 28 | Unique quiz_session_id for the quiz. 29 | The quiz session id will be returned with the first request and it should be passed with subsequent requests. 30 | More information can be found: https://docs.constructor.com/reference/configuration-quizzes 31 | */ 32 | public let quizSessionID: String 33 | 34 | /** 35 | Id of the quiz 36 | */ 37 | public let quizID: String 38 | } 39 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Result/Responses/CIORecommendationsResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIORecommendationsResponse.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Struct representing the recommendations data response from the server. 13 | */ 14 | public struct CIORecommendationsResponse { 15 | /** 16 | Pod information 17 | */ 18 | public let pod: CIORecommendationsPod 19 | 20 | /** 21 | List of results returned for the recommendations query 22 | */ 23 | public let results: [CIOResult] 24 | 25 | /** 26 | Total number of results for the query 27 | */ 28 | public let totalNumResults: Int 29 | 30 | /** 31 | Result ID of the result set returned 32 | */ 33 | public let resultID: String 34 | 35 | /** 36 | Request object used to retrieve the Recommendations Response 37 | */ 38 | public var request: JSONObject 39 | } 40 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Session/CIOSessionManagerDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOSessionManagerDelegate.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol CIOSessionManagerDelegate: AnyObject { 12 | func sessionDidChange(from: Int, to: Int) 13 | } 14 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Session/Date/CurrentTimeDateProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurrentTimeDateProvider.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | struct CurrentTimeDateProvider: DateProvider { 12 | 13 | init() {} 14 | 15 | func provideDate() -> Date { 16 | return Date() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Session/Date/DateProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateProvider.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol DateProvider { 12 | func provideDate() -> Date 13 | } 14 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Session/Persistence/CIOSessionLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOSessionLoader.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | struct CIOSessionLoader: SessionLoader { 12 | 13 | init() {} 14 | 15 | func loadSession() -> Session? { 16 | if let data = UserDefaults.standard.object(forKey: Constants.Session.key) as? Data { 17 | return NSKeyedUnarchiver.unarchiveObject(with: data) as? Session 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | func saveSession(_ session: Session) { 24 | let data = NSKeyedArchiver.archivedData(withRootObject: session) 25 | UserDefaults.standard.set(data, forKey: Constants.Session.key) 26 | } 27 | 28 | func clearSession() { 29 | UserDefaults.standard.removeObject(forKey: Constants.Session.key) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Session/Persistence/SessionLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionLoader.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol SessionLoader { 12 | 13 | func loadSession() -> Session? 14 | func saveSession(_ session: Session) 15 | 16 | func clearSession() 17 | } 18 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Session/Session.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Session.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public class Session: NSObject, NSCoding { 12 | public var id: Int 13 | public let createdAt: TimeInterval 14 | 15 | public init(id: Int, createdAt: TimeInterval) { 16 | self.id = id 17 | self.createdAt = createdAt 18 | } 19 | 20 | public required init?(coder aDecoder: NSCoder) { 21 | self.id = aDecoder.decodeInteger(forKey: Constants.Session.id) 22 | self.createdAt = aDecoder.decodeDouble(forKey: Constants.Session.createdAt) 23 | } 24 | 25 | public func encode(with aCoder: NSCoder) { 26 | aCoder.encode(self.id, forKey: Constants.Session.id) 27 | aCoder.encode(self.createdAt, forKey: Constants.Session.createdAt) 28 | } 29 | 30 | public func setSessionID(sessionID: Int) { 31 | self.id = sessionID 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/Logic/Session/SessionManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionManager.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol SessionManager: AnyObject { 12 | var delegate: CIOSessionManagerDelegate? { get set } 13 | 14 | func getSessionWithIncrement() -> Int 15 | func getSessionWithoutIncrement() -> Int 16 | 17 | func setSessionID(id: Int) 18 | 19 | func setup() 20 | } 21 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/CustomCell/SearchResultCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOAutocompleteCell.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol CIOAutocompleteCell { 12 | func setup(result: CIOAutocompleteResult, searchTerm: String, highlighter: CIOHighlighter) 13 | } 14 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/DefaultSearchItemCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultSearchItemCell.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class DefaultSearchItemCell: UITableViewCell, CIOAutocompleteCell { 12 | 13 | @IBOutlet public weak var labelText: UILabel! 14 | 15 | override public func awakeFromNib() { 16 | super.awakeFromNib() 17 | } 18 | 19 | public func setup(result: CIOAutocompleteResult, searchTerm: String, highlighter: CIOHighlighter) { 20 | if let group = result.group { 21 | let groupString = NSMutableAttributedString() 22 | 23 | groupString.append(highlighter.highlight(searchTerm: searchTerm, itemTitle: result.result.value)) 24 | 25 | let fontGroup = Constants.UI.Font.defaultFontNormal.withSize(11) 26 | let groupAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: fontGroup, 27 | NSAttributedString.Key.foregroundColor: Constants.UI.Color.defaultFontColorNormal] 28 | 29 | groupString.append(NSAttributedString.build(string: "\nin \(group.displayName)", attributes: groupAttributes)) 30 | self.labelText.attributedText = groupString 31 | } else { 32 | self.labelText.attributedText = highlighter.highlight(searchTerm: searchTerm, itemTitle: result.result.value) 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/Empty/EmptyScreenView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EmptyScreenView.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class EmptyScreenView: UIView { 12 | 13 | override public func awakeFromNib() { 14 | super.awakeFromNib() 15 | self.backgroundColor = CIOStyle.colorLightGrey() 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/Error/CIOErrorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOErrorView.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | Conform to this protocol if you want to use a custom error view. 13 | */ 14 | public protocol CIOErrorView: NSObjectProtocol { 15 | /** 16 | Returns a UIView instance. If your UIView implements this protocol, simply return self. 17 | 18 | - returns: UIView to be added to the view hierarchy if an error occurs. 19 | */ 20 | func asView() -> UIView 21 | 22 | /** 23 | Method called when if an error occurs. 24 | 25 | - parameter errorString: String value of an error that occurred. 26 | */ 27 | func setErrorString(errorString: String) 28 | } 29 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/SearchBar/CIOSearchBarDisplayMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOSearchBarDisplayMode.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public enum CIOSearchBarDisplayMode { 12 | case tableViewHeader 13 | case navigationBar 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/SearchBar/CustomSearchBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomSearchBar.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class CustomSearchBar: UISearchBar { 12 | 13 | public var shouldShowCancelButton = false 14 | 15 | public init() { 16 | super.init(frame: .zero) 17 | } 18 | 19 | public override init(frame: CGRect) { 20 | super.init(frame: frame) 21 | } 22 | 23 | public required init?(coder aDecoder: NSCoder) { 24 | super.init(coder: aDecoder) 25 | } 26 | 27 | override public func setShowsCancelButton(_ showsCancelButton: Bool, animated: Bool) { 28 | super.setShowsCancelButton(self.shouldShowCancelButton && self.isFirstResponder, animated: animated) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/SearchBar/CustomSearchController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomSearchController.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class CustomSearchController: UISearchController { 12 | 13 | @objc lazy var searchBarPvt: CustomSearchBar = { 14 | [unowned self] in 15 | let customSearchBar = CustomSearchBar(frame: CGRect.zero) 16 | return customSearchBar 17 | }() 18 | 19 | override public var searchBar: UISearchBar { 20 | get { 21 | return searchBarPvt 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/Style/CIOStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOStyle.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public class CIOStyle { 12 | 13 | class func colorLightGrey() -> UIColor { 14 | let val = 245 15 | return UIColor.RGB(val, green: val, blue: val) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/ViewModel/AbstractAutocompleteViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractAutocompleteViewModel.swift 3 | // AutocompleteClient 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol AbstractAutocompleteViewModel { 12 | 13 | var results: [AutocompleteViewModelSection] { get set } 14 | var delegate: AutocompleteViewModelDelegate? { get set } 15 | var screenTitle: String { get set } 16 | var modelSorter: (String, String) -> Bool { get set } 17 | var searchTerm: String { get } 18 | 19 | func set(searchResult: AutocompleteResult, completionHandler: @escaping () -> Void) 20 | 21 | func getResult(atIndexPath indexPath: IndexPath) -> CIOAutocompleteResult 22 | func getSectionName(atIndex index: Int) -> String 23 | 24 | } 25 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/ViewModel/AutocompleteResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteResult.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public class AutocompleteResult { 12 | public let query: CIOAutocompleteQuery 13 | public var response: CIOAutocompleteResponse? 14 | public let timestamp: TimeInterval 15 | 16 | public init(query: CIOAutocompleteQuery, timestamp: TimeInterval = Date().timeIntervalSince1970) { 17 | self.query = query 18 | self.timestamp = timestamp 19 | } 20 | 21 | public func isInitiatedAfter(result: AutocompleteResult) -> Bool { 22 | return self.timestamp > result.timestamp 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/ViewModel/AutocompleteViewModelDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteViewModelDelegate.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol AutocompleteViewModelDelegate: AnyObject { 12 | func viewModel(_ viewModel: AbstractAutocompleteViewModel, didIgnoreResult result: AutocompleteResult) 13 | func viewModel(_ viewModel: AbstractAutocompleteViewModel, didSetResult result: AutocompleteResult) 14 | } 15 | -------------------------------------------------------------------------------- /AutocompleteClient/FW/UI/ViewModel/AutocompleteViewModelSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteViewModelSection.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | public struct AutocompleteViewModelSection { 12 | public let items: [CIOAutocompleteResult] 13 | public let sectionName: String 14 | 15 | public init(items: [CIOAutocompleteResult], sectionName: String) { 16 | self.items = items 17 | self.sectionName = sectionName 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AutocompleteClient/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 4.1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AutocompleteClient/Resources/constructor-io-error-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/AutocompleteClient/Resources/constructor-io-error-icon.png -------------------------------------------------------------------------------- /AutocompleteClient/Resources/constructor-io-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/AutocompleteClient/Resources/constructor-io-logo.png -------------------------------------------------------------------------------- /AutocompleteClient/Utils/Collection/Collection+MapKeys.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Collection+MapKeys.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | extension Dictionary { 12 | func mapKeys(_ mapping: (_ key: Key) -> T) -> [T: Value] { 13 | var newDictionary: [T: Value] = [:] 14 | for (key, value) in self { 15 | newDictionary[mapping(key)] = value 16 | } 17 | 18 | return newDictionary 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AutocompleteClient/Utils/Color/UIColor+RGB.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+RGB.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | class func RGB(_ red: Int, green: Int, blue: Int) -> UIColor { 13 | return self.RGBA(red, green: green, blue: blue, alpha: 255) 14 | } 15 | 16 | class func RGBA(_ red: Int, green: Int, blue: Int, alpha: CGFloat) -> UIColor { 17 | return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: alpha) 18 | } 19 | 20 | class func hex(rgb: Int) -> UIColor { 21 | return self.RGB((rgb >> 16) & 0xFF, green: (rgb >> 8) & 0xFF, blue: rgb & 0xFF) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AutocompleteClient/Utils/String/NSAttributedString+Build.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+Build.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | extension NSAttributedString { 12 | 13 | static func build(string: String, attributes: [NSAttributedString.Key: Any]) -> NSAttributedString { 14 | return NSAttributedString(string: string, attributes: attributes) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AutocompleteClient/Utils/String/String+SearchSuggestionsSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+SearchSuggestionsSection.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | func isSearchSuggestionString() -> Bool { 13 | return self.lowercased().replacingOccurrences(of: " ", with: "") == "searchsuggestions" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AutocompleteClient/Utils/String/String+Trim.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Trim.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | func trim() -> String { 13 | return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AutocompleteClient/Utils/UI/UISearchBar+TextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UISearchBar+TextField.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UISearchBar { 12 | func searchTextField() -> UITextField? { 13 | return self.findSubview({ view -> Bool in view is UITextField }) as? UITextField 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AutocompleteClient/Utils/UI/UIView+FadeInOut.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+FadeInOut.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIView { 12 | func fadeIn(duration: TimeInterval, completion: ((Bool) -> Void)? = nil) { 13 | self.alpha = 0.0 14 | UIView.animate(withDuration: duration, animations: { [weak self] in 15 | self?.alpha = 1.0 16 | }, completion: completion) 17 | } 18 | 19 | func fadeOutAndRemove(duration: TimeInterval, completion: ((Bool) -> Void)? = nil) { 20 | UIView.animate(withDuration: duration, animations: { [weak self] in 21 | self?.alpha = 0.0 22 | }, completion: { [weak self] completed in 23 | self?.removeFromSuperview() 24 | completion?(completed) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AutocompleteClient/Utils/UI/UIView+FindSubview.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+FindSubview.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UIView { 13 | func findSubview(_ filter: (UIView) -> Bool) -> UIView? { 14 | for view in self.subviews { 15 | if filter(view) { 16 | return view 17 | } else if let subview = view.findSubview(filter) { 18 | return subview 19 | } 20 | } 21 | return nil 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/API/Error/ErrorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ErrorTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class ErrorTests: XCTestCase { 13 | 14 | func testUnknownErrorHasCorrectCode() { 15 | XCTAssertEqual(NSError.unknownError().code, kConstructorUnknownErrorCode) 16 | } 17 | 18 | func testParseErrorHasCorrectCode() { 19 | XCTAssertEqual(NSError.jsonParseError().code, kConstructorJSONErrorCode) 20 | } 21 | 22 | func testCIOErrorReturnsNonNilErrorDescription() { 23 | XCTAssertNotNil(CIOError(errorType: .invalidResponse).errorDescription) 24 | } 25 | 26 | func testCIOErrorWithReturnsNonNilErrorMessage() { 27 | XCTAssertNotNil(CIOError(errorType: .badRequest, errorMessage: "Invalid parameter supplied with the request.").errorMessage) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/API/Parser/MockResponseParserDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MockResponseParserDelegate.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import Foundation 11 | 12 | class MockResponseParserDelegate: NSObject, ResponseParserDelegate { 13 | 14 | var shouldParseResultInGroup: ((_ result: CIOResult, _ group: CIOGroup?) -> Bool)? = { _, _ in return true } 15 | 16 | func shouldParseResult(result: CIOResult, inGroup group: CIOGroup?) -> Bool? { 17 | return self.shouldParseResultInGroup?(result, group) 18 | } 19 | 20 | func maximumGroupsShownPerResult(result: CIOResult, at index: Int) -> Int { 21 | return 1 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Request/Matchers/CIOBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOBuilder.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import XCTest 10 | 11 | class CIOBuilder { 12 | 13 | let expectation: XCTestExpectation 14 | let builder: Builder 15 | 16 | init(expectation: String, builder: @escaping Builder) { 17 | self.expectation = XCTestExpectation(description: expectation) 18 | self.builder = builder 19 | } 20 | 21 | func create() -> Builder { 22 | return { request in 23 | // at this point we know that request has been made and we can fullfil the expectation and delegate the request object 24 | // to the builder provided 25 | self.expectation.fulfill() 26 | return self.builder(request) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Request/Matchers/Matcher+Regex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Matcher+Regex.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import XCTest 10 | 11 | // Returns a MockingJay Matcher if the URL string matches a regex 12 | public func regex(_ pattern: String, prepare: Bool = true) -> Matcher { 13 | return { request in 14 | let absoluteURLString = request.url!.absoluteString 15 | 16 | let preparedPattern = prepare ? prepareRegexPattern(pattern) : pattern 17 | do { 18 | let matchRange = try NSRegularExpression(pattern: preparedPattern, options: []).rangeOfFirstMatch(in: absoluteURLString, options: [], range: NSRange(location: 0, length: absoluteURLString.count)) 19 | return matchRange.location == 0 && matchRange.length == absoluteURLString.count 20 | } catch { 21 | return false 22 | } 23 | } 24 | } 25 | 26 | // escape occurences of '?' and '/' 27 | private func prepareRegexPattern(_ pattern: String) -> String { 28 | return pattern.replacingOccurrences(of: "/", with: "\\/") 29 | .replacingOccurrences(of: "?", with: "\\?") 30 | } 31 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Request/Mock/CIOGroup+Mock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOGroup+Mock.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import ConstructorAutocomplete 10 | import XCTest 11 | 12 | public extension CIOGroup { 13 | class func mock(withName name: String? = nil) -> CIOGroup { 14 | let naem = name ?? "group" 15 | return CIOGroup(displayName: naem, groupID: naem, path: "path/to/group") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Request/Mock/CIOResult+Mock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOAutocompleteResult+Mock.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import ConstructorAutocomplete 10 | import XCTest 11 | 12 | public extension CIOAutocompleteResult { 13 | 14 | class func mock(withValue value: String, group: CIOGroup? = nil) -> CIOAutocompleteResult { 15 | let json: [String: Any] = TestResource.load(name: TestResource.Response.singleResultJSONFilename).toJSONDictionary()! 16 | return CIOAutocompleteResult(result: CIOResult(json: json)!, group: group) 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Request/Mock/MockCommons.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MockCommons.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import OHHTTPStubs 10 | import XCTest 11 | 12 | public typealias Matcher = OHHTTPStubsTestBlock 13 | public typealias Builder = OHHTTPStubsResponseBlock 14 | 15 | public func http(_ statusCode: Int32, data: Data = "".data(using: String.Encoding.utf8)!) -> OHHTTPStubsResponseBlock { 16 | return { _ in 17 | return OHHTTPStubsResponse(data: data, statusCode: statusCode, headers: nil) 18 | } 19 | } 20 | 21 | public func noConnectivity() -> OHHTTPStubsResponseBlock { 22 | return { _ in 23 | let error = NSError(domain: NSURLErrorDomain, code: URLError.notConnectedToInternet.rawValue, userInfo: nil) 24 | return OHHTTPStubsResponse(error: error) 25 | } 26 | } 27 | 28 | @discardableResult 29 | public func stub(_ matcher: @escaping Matcher, _ builder: @escaping Builder) -> OHHTTPStubsDescriptor { 30 | return stub(condition: matcher, response: builder) 31 | } 32 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Request/QueryItemCollection/QueryItemCollectionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QueryItemCollectionTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class QueryItemCollectionTests: XCTestCase { 13 | 14 | func testQueryItemCollection_Remove() { 15 | var collection = QueryItemCollection() 16 | collection.remove(name: "key") 17 | } 18 | 19 | func testQueryItemCollection_SubscriptGetter() { 20 | let collection = QueryItemCollection() 21 | _ = collection["key"] 22 | } 23 | 24 | func testQueryItemCollection_SubscriptSetter() { 25 | var collection = QueryItemCollection() 26 | collection["key"] = [URLQueryItem(name: "name", value: "value")] 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Session/ClosureDateProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClosureDateProvider.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import UIKit 11 | 12 | class ClosureDateProvider: DateProvider { 13 | 14 | var provideDateClosure: () -> Date 15 | 16 | init(provideDateClosure: @escaping () -> Date) { 17 | self.provideDateClosure = provideDateClosure 18 | } 19 | 20 | func provideDate() -> Date { 21 | return self.provideDateClosure() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Session/ClosureSessionManagerDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClosureSessionManagerDelegate.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import ConstructorAutocomplete 10 | 11 | class ClosureSessionManagerDelegate: CIOSessionManagerDelegate { 12 | 13 | let sessionChangeHandler: (_ from: Int, _ to: Int) -> Void 14 | 15 | init(sessionChangeHandler: @escaping (_ from: Int, _ to: Int) -> Void) { 16 | self.sessionChangeHandler = sessionChangeHandler 17 | } 18 | 19 | func sessionDidChange(from: Int, to: Int) { 20 | self.sessionChangeHandler(from, to) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/Logic/Session/NoSessionLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoSessionLoader.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | 11 | class NoSessionLoader: SessionLoader { 12 | func loadSession() -> Session? { 13 | return nil 14 | } 15 | func saveSession(_ session: Session) {} 16 | 17 | func clearSession() {} 18 | } 19 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/UI/SearchBar/SearchBarTextFieldTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchBarTextFieldTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class SearchBarTextFieldTests: XCTestCase { 13 | 14 | func testTextFieldExtractFromSearchBar() { 15 | let searchBar = UISearchBar(frame: CGRect.zero) 16 | searchBar.layoutIfNeeded() 17 | XCTAssertNotNil(searchBar.searchTextField()) 18 | } 19 | 20 | func testCustomSearchBar_WithDefaultInitializer() { 21 | let searchBar = CustomSearchBar() 22 | searchBar.setShowsCancelButton(true, animated: true) 23 | } 24 | 25 | func testCustomSearchBar_WithFrameInitializer() { 26 | let searchBar = CustomSearchBar(frame: .zero) 27 | searchBar.setShowsCancelButton(true, animated: true) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/UI/ViewModel/AutocompleteResultCountTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteResultCountTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class AutocompleteResultCountTests: XCTestCase { 13 | 14 | func testAutocompleteResultCount_NumResultsInitializer() { 15 | let resultCount = AutocompleteResultCount(numResults: 1) 16 | XCTAssertNotNil(resultCount.numResults) 17 | XCTAssertNil(resultCount.numResultsForSection) 18 | } 19 | 20 | func testAutocompleteResultCount_NumResultsForSectionInitializer() { 21 | let resultCount = AutocompleteResultCount(numResultsForSection: [:]) 22 | XCTAssertNil(resultCount.numResults) 23 | XCTAssertNotNil(resultCount.numResultsForSection) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/UI/ViewModel/AutocompleteResultTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteResultTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class AutocompleteResultTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testIsAfter_ifCorrectTimestampsArePassed() { 25 | let query = CIOAutocompleteQuery(query: "") 26 | let earlyResult = AutocompleteResult(query: query, timestamp: 10) 27 | let lateResult = AutocompleteResult(query: query, timestamp: 20) 28 | XCTAssertTrue(lateResult.isInitiatedAfter(result: earlyResult), "isAfter should return true if earlier initiated result is passed as a parameter") 29 | } 30 | 31 | func testIsAfter_ifIncorrectTimestampsArePassed() { 32 | let query = CIOAutocompleteQuery(query: "") 33 | let earlyResult = AutocompleteResult(query: query, timestamp: 20) 34 | let lateResult = AutocompleteResult(query: query, timestamp: 10) 35 | XCTAssertFalse(lateResult.isInitiatedAfter(result: earlyResult), "isAfter should return false if later initiated result is passed as a parameter") 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /AutocompleteClientTests/FW/UI/ViewModel/ClosureAutocompleteViewModelDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClosureAutocompleteViewModelDelegate.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import ConstructorAutocomplete 10 | import UIKit 11 | 12 | public class ClosureAutocompleteViewModelDelegate: AutocompleteViewModelDelegate { 13 | 14 | public var onIgnoreResult: ((AutocompleteResult) -> Void)? 15 | public var onSetResult: ((AutocompleteResult) -> Void)? 16 | 17 | public init(viewModel: AutocompleteViewModel) { 18 | viewModel.delegate = self 19 | } 20 | 21 | public func viewModel(_ viewModel: AbstractAutocompleteViewModel, didSetResult result: AutocompleteResult) { 22 | self.onSetResult?(result) 23 | } 24 | 25 | public func viewModel(_ viewModel: AbstractAutocompleteViewModel, didIgnoreResult result: AutocompleteResult) { 26 | self.onIgnoreResult?(result) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Resources/response_browse_facet_options_json.json: -------------------------------------------------------------------------------- 1 | { 2 | "response": { 3 | "facets": [ 4 | { 5 | "display_name": "Brand", 6 | "name": "brand", 7 | "type": "multiple", 8 | "options": [ 9 | { 10 | "status": "", 11 | "count": 2460, 12 | "display_name": "Brand1", 13 | "value": "brand1", 14 | "data": null 15 | }, 16 | { 17 | "status": "", 18 | "count": 662, 19 | "display_name": "Brand2", 20 | "value": "brand2", 21 | "data": null 22 | }, 23 | { 24 | "status": "", 25 | "count": 409, 26 | "display_name": "Brand3", 27 | "value": "brand3", 28 | "data": null 29 | } 30 | ], 31 | "hidden": false, 32 | "data": {} 33 | } 34 | ] 35 | }, 36 | "result_id": "8943b599-4d16-432a-ba28-cb9eb95e4625", 37 | "request": { 38 | "facet_name": "brand", 39 | "fmt_options": { 40 | "show_hidden_facets": true, 41 | "groups_start": "current", 42 | "groups_max_depth": 1, 43 | "show_hidden_fields": false, 44 | "show_protected_facets": false 45 | }, 46 | "term": "", 47 | "page": 1, 48 | "num_results_per_page": 20, 49 | "sort_by": "relevance", 50 | "sort_order": "descending", 51 | "section": "Products" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Resources/response_browse_facets_json.json: -------------------------------------------------------------------------------- 1 | { 2 | "response": { 3 | "facets": [ 4 | { 5 | "display_name": "Brand", 6 | "name": "brand", 7 | "type": "multiple", 8 | "hidden": false, 9 | "data": {} 10 | }, 11 | { 12 | "display_name": "Category", 13 | "name": "category", 14 | "type": "multiple", 15 | "hidden": false, 16 | "data": {} 17 | }, 18 | { 19 | "display_name": "Collection", 20 | "name": "collection", 21 | "type": "multiple", 22 | "hidden": false, 23 | "data": {} 24 | }, 25 | { 26 | "display_name": "Lining Level", 27 | "name": "lining", 28 | "type": "multiple", 29 | "hidden": false, 30 | "data": {} 31 | }, 32 | { 33 | "display_name": "Color", 34 | "name": "color", 35 | "type": "multiple", 36 | "hidden": false, 37 | "data": {} 38 | } 39 | ], 40 | "total_num_results": 9 41 | }, 42 | "result_id": "aa13f189-7820-49c0-bc4f-735f75c2dcdc", 43 | "request": { 44 | "page": 1, 45 | "num_results_per_page": 5, 46 | "term": "", 47 | "fmt_options": { 48 | "groups_start": "current", 49 | "groups_max_depth": 1, 50 | "show_hidden_facets": false, 51 | "show_hidden_fields": false, 52 | "show_protected_facets": false 53 | }, 54 | "sort_by": "relevance", 55 | "sort_order": "descending", 56 | "section": "Products" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Resources/response_json_single_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "groups": [{ 4 | "display_name": "Drama", 5 | "group_id": "18", 6 | "path": null 7 | }, 8 | { 9 | "display_name": "Adventure", 10 | "group_id": "12", 11 | "path": null 12 | }, 13 | { 14 | "display_name": "Fantasy", 15 | "group_id": "14", 16 | "path": null 17 | }, 18 | { 19 | "display_name": "Family", 20 | "group_id": "10751", 21 | "path": null 22 | }, 23 | { 24 | "display_name": "Action", 25 | "group_id": "28", 26 | "path": null 27 | }, 28 | { 29 | "display_name": "Animation", 30 | "group_id": "16", 31 | "path": null 32 | }, 33 | { 34 | "display_name": "Science Fiction", 35 | "group_id": "878", 36 | "path": null 37 | } 38 | ], 39 | "id": "titans" 40 | }, 41 | "matched_terms": [ 42 | "titans" 43 | ], 44 | "value": "titans" 45 | } 46 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Resources/response_quiz_next_question.json: -------------------------------------------------------------------------------- 1 | { 2 | "next_question": { 3 | "id": 1, 4 | "title": "Sample single select question", 5 | "description": "Sample description", 6 | "type": "single", 7 | "cta_text": "Next", 8 | "images": { 9 | "primary_url": "https://example.com/image", 10 | "primary_alt": "Example image", 11 | "secondary_url": null, 12 | "secondary_alt": null 13 | }, 14 | "options": [ 15 | { 16 | "id": 1, 17 | "value": "Who", 18 | "attribute": { 19 | "name": "group_id", 20 | "value": "test-value" 21 | }, 22 | "images": { 23 | "primary_url": "https://example.com/image", 24 | "primary_alt": "Example image", 25 | "secondary_url": null, 26 | "secondary_alt": null 27 | } 28 | }, 29 | { 30 | "id": 2, 31 | "value": "What", 32 | "attribute": { 33 | "name": "group_id", 34 | "value": "test-value" 35 | }, 36 | "images": null 37 | } 38 | ] 39 | }, 40 | "quiz_version_id": "11db5ac7-67e1-4000-9000-414d8425cab3", 41 | "quiz_session_id": "session-67e1-4000-9000-414d8425cab3", 42 | "quiz_id": "123" 43 | } 44 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Resources/response_search_redirect.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "fmt_options": { 4 | "groups_max_depth": 1, 5 | "groups_start": "current" 6 | }, 7 | "num_results_per_page": 24, 8 | "page": 1, 9 | "section": "Products", 10 | "sort_by": "relevance", 11 | "sort_order": "descending", 12 | "term": "dior", 13 | "us": ["COUNTRY_US"] 14 | }, 15 | "response": { 16 | "redirect": { 17 | "data": { 18 | "match_id": 16257, 19 | "rule_id": 8860, 20 | "url": "/brand/dior" 21 | }, 22 | "matched_terms": ["dior"], 23 | "matched_user_segments": null 24 | } 25 | }, 26 | "result_id": "cc5752d6-41a5-4fdf-a461-622d91306ee2" 27 | } 28 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Test Utils/Bundle/Bundle+Test.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bundle+Test.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import XCTest 10 | 11 | extension Bundle { 12 | class func testBundle() -> Bundle { 13 | // pass any class from our test target 14 | return Bundle(for: CIOAutocompleteResponseParserTests.self) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Test Utils/CIOResponse+SearchSuggestions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIOAutocompleteResponse+SearchSuggestions.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import ConstructorAutocomplete 10 | import XCTest 11 | 12 | extension CIOAutocompleteResponse { 13 | func getSearchSuggestions() -> [CIOAutocompleteResult]? { 14 | return self.sections["Search Suggestions"] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Test Utils/Constants/TestConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestConstants.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | let kRegexTimestamp = "[1-9][0-9]*" 13 | let kRegexClientID = "([A-Z0-9-])*" 14 | let kRegexSession = "[0-9]*" 15 | let kRegexAutocompleteKey = "[a-zA-Z-_0-9]*" 16 | let kRegexVersion = "cioios-[\\d\\.]*::[\\d\\.]*" 17 | 18 | struct TestConstants { 19 | static let defaultUserInterfaceExpectationTimeout: TimeInterval = 50.0 20 | static let defaultExpectationTimeout: TimeInterval = 1.5 21 | static let testApiKey = "key_OucJxxrfiTVUQx0C" 22 | static let testConfig = ConstructorIOConfig(apiKey: testApiKey) 23 | static let defaultSegments = "us=cio-app&us=cio-ios" 24 | 25 | static func testConstructor(_ config: ConstructorIOConfig = TestConstants.testConfig) -> ConstructorIO { 26 | let constructor = ConstructorIO(config: config) 27 | constructor.sessionManager = CIOSessionManager(dateProvider: CurrentTimeDateProvider(), timeout: Constants.Query.sessionIncrementTimeoutInSeconds, sessionLoader: NoSessionLoader()) 28 | return constructor 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Test Utils/JSON/Data+ToJSON.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+ToJSON.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import XCTest 10 | 11 | public extension Data { 12 | func toJSONDictionary() -> [String: Any]? { 13 | do { 14 | return try JSONSerialization.jsonObject(with: self, options: []) as? [String: Any] 15 | } catch { 16 | return nil 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Test Utils/XCTest/ExpectationHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExpectationHandler.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import XCTest 10 | 11 | class ExpectationHandler { 12 | let expectation: XCTestExpectation 13 | 14 | init(expectation: XCTestExpectation) { 15 | self.expectation = expectation 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Test Utils/XCTest/XCTest+TimeoutFail.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XCTest+TimeoutFail.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import XCTest 10 | 11 | extension XCTestCase { 12 | 13 | func defaultTimeoutFailureHandler() -> ((_ error: Error?) -> Void) { 14 | return { error in 15 | if error != nil { 16 | XCTFail("Test timed out.") 17 | } 18 | } 19 | } 20 | 21 | func waitForExpectationWithDefaultHandler(_ timeout: TimeInterval = TestConstants.defaultExpectationTimeout) { 22 | self.waitForExpectations(timeout: timeout, handler: self.defaultTimeoutFailureHandler()) 23 | } 24 | 25 | func wait(for expectation: XCTestExpectation) { 26 | self.wait(for: [expectation], timeout: 1.0) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Utils/Color/UIColorRGBConversionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColorRGBConversionTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class UIColorRGBConversionTests: XCTestCase { 13 | 14 | func testColor_RGBInitializer() { 15 | let color = UIColor.RGB(250, green: 200, blue: 33) 16 | XCTAssertNotNil(color) 17 | } 18 | 19 | func testColor_RGBAInitializer() { 20 | let color = UIColor.RGBA(250, green: 200, blue: 33, alpha: 0.5) 21 | XCTAssertNotNil(color) 22 | } 23 | 24 | func testColor_HexInitializer() { 25 | let color = UIColor.hex(rgb: 123456) 26 | XCTAssertNotNil(color) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Utils/String/SearchSuggestionStringConversionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchSuggestionStringConversionTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class SearchSuggestionStringConversionTests: XCTestCase { 13 | 14 | func testValidSearchSuggestionString() { 15 | XCTAssertTrue("SEARCH SuggestionS ".isSearchSuggestionString()) 16 | } 17 | 18 | func testInvalidSearchSuggestionString() { 19 | XCTAssertFalse("SEARCH Suggestionz".isSearchSuggestionString()) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Utils/String/StringTrimTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringTrimTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class StringTrimTests: XCTestCase { 13 | 14 | func testStrinTrimRemovedTrailingSpaces() { 15 | let original = "abc " 16 | XCTAssertEqual(original.trim(), "abc") 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /AutocompleteClientTests/Utils/UI/UIViewAnimationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewAnimationTests.swift 3 | // AutocompleteClientTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | @testable import ConstructorAutocomplete 10 | import XCTest 11 | 12 | class UIViewAnimationTests: XCTestCase { 13 | 14 | func testViewFadeIn() { 15 | let expectation = XCTestExpectation(description: "View alpha should be 1 after completion handler is called.") 16 | 17 | let view = UIView(frame: .zero) 18 | view.alpha = 0 19 | 20 | view.fadeIn(duration: 0.5, completion: { _ in 21 | XCTAssertEqual(view.alpha, 1.0) 22 | expectation.fulfill() 23 | }) 24 | 25 | self.wait(for: [expectation], timeout: 1.0) 26 | } 27 | 28 | func testViewFadeOut() { 29 | let expectation = XCTestExpectation(description: "View alpha should be 0 after completion handler is called.") 30 | 31 | let view = UIView(frame: .zero) 32 | view.alpha = 1 33 | 34 | view.fadeOutAndRemove(duration: 0.5, completion: { _ in 35 | XCTAssertEqual(view.alpha, 0.0) 36 | expectation.fulfill() 37 | }) 38 | 39 | self.wait(for: [expectation], timeout: 1.0) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /ConstructorAutocomplete.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/ConstructorAutocomplete.dia -------------------------------------------------------------------------------- /ConstructorAutocomplete.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'ConstructorAutocomplete' 3 | spec.version = '4.1.0' 4 | spec.license = { :type => 'MIT', :file => 'LICENSE' } 5 | spec.homepage = 'https://www.constructor.io' 6 | spec.authors = { 'Zubin Tiku' => 'zubin@constructor.io', 'Christopher Gee' => 'christopher@constructor.io', 'Jimmy Li' => 'jimmy@constructor.io' } 7 | spec.summary = 'Constructor.io iOS Client' 8 | spec.source = { :git => 'https://github.com/Constructor-io/constructorio-client-swift.git', :tag => 'v4.1.0' } 9 | spec.platform = :ios, '11.0' 10 | spec.source_files = 'AutocompleteClient/**/*.swift' 11 | spec.framework = 'UIKit' 12 | spec.swift_versions = ['4.0', '4.1', '4.2', '5'] 13 | spec.ios.resource_bundle = { 'ConstructorAutocomplete' => ['AutocompleteClient/Resources/*.png', 'AutocompleteClient/**/*.xib'] } 14 | end 15 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | gem 'slather' 6 | gem 'jazzy' 7 | gem 'xcodeproj' 8 | gem "rexml", ">= 3.3.6" 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Constructor.io Corporation 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "ConstructorIO", 6 | 7 | platforms: [ 8 | .iOS(.v11) 9 | ], 10 | products: [ 11 | .library(name: "ConstructorAutocomplete", targets: ["ConstructorAutocomplete"]) 12 | ], 13 | targets: [ 14 | .target(name: "ConstructorAutocomplete", 15 | path: "AutocompleteClient/") 16 | ] 17 | ) 18 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | xcodeproj "AutocompleteClient.xcodeproj" 2 | 3 | source 'https://github.com/CocoaPods/Specs.git' 4 | 5 | use_frameworks! 6 | 7 | platform :ios, '11.0' 8 | 9 | inhibit_all_warnings! 10 | 11 | target 'UserApplication' do 12 | pod 'Kingfisher' 13 | end 14 | 15 | target 'AutocompleteClientTests' do 16 | pod 'OHHTTPStubs/Swift' 17 | end 18 | 19 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Kingfisher (4.10.1) 3 | - OHHTTPStubs/Core (6.1.0) 4 | - OHHTTPStubs/Default (6.1.0): 5 | - OHHTTPStubs/Core 6 | - OHHTTPStubs/JSON 7 | - OHHTTPStubs/NSURLSession 8 | - OHHTTPStubs/OHPathHelpers 9 | - OHHTTPStubs/JSON (6.1.0): 10 | - OHHTTPStubs/Core 11 | - OHHTTPStubs/NSURLSession (6.1.0): 12 | - OHHTTPStubs/Core 13 | - OHHTTPStubs/OHPathHelpers (6.1.0) 14 | - OHHTTPStubs/Swift (6.1.0): 15 | - OHHTTPStubs/Default 16 | 17 | DEPENDENCIES: 18 | - Kingfisher 19 | - OHHTTPStubs/Swift 20 | 21 | SPEC REPOS: 22 | https://github.com/cocoapods/specs.git: 23 | - Kingfisher 24 | - OHHTTPStubs 25 | 26 | SPEC CHECKSUMS: 27 | Kingfisher: c148cd7b47ebde9989f6bc7c27dcaa79d81279a0 28 | OHHTTPStubs: 1e21c7d2c084b8153fc53d48400d8919d2d432d0 29 | 30 | PODFILE CHECKSUM: 8e6d7727bc494546363e0c7b4bb5c24a0e69cf70 31 | 32 | COCOAPODS: 1.7.3 33 | -------------------------------------------------------------------------------- /Pods/Kingfisher/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Wei Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Pods/Kingfisher/Sources/Box.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Box.swift 3 | // Kingfisher 4 | // 5 | // Created by Wei Wang on 2018/3/17. 6 | // Copyright (c) 2018 Wei Wang 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | 28 | class Box { 29 | let value: T 30 | 31 | init(_ value: T) { 32 | self.value = value 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Kingfisher (4.10.1) 3 | - OHHTTPStubs/Core (6.1.0) 4 | - OHHTTPStubs/Default (6.1.0): 5 | - OHHTTPStubs/Core 6 | - OHHTTPStubs/JSON 7 | - OHHTTPStubs/NSURLSession 8 | - OHHTTPStubs/OHPathHelpers 9 | - OHHTTPStubs/JSON (6.1.0): 10 | - OHHTTPStubs/Core 11 | - OHHTTPStubs/NSURLSession (6.1.0): 12 | - OHHTTPStubs/Core 13 | - OHHTTPStubs/OHPathHelpers (6.1.0) 14 | - OHHTTPStubs/Swift (6.1.0): 15 | - OHHTTPStubs/Default 16 | 17 | DEPENDENCIES: 18 | - Kingfisher 19 | - OHHTTPStubs/Swift 20 | 21 | SPEC REPOS: 22 | https://github.com/cocoapods/specs.git: 23 | - Kingfisher 24 | - OHHTTPStubs 25 | 26 | SPEC CHECKSUMS: 27 | Kingfisher: c148cd7b47ebde9989f6bc7c27dcaa79d81279a0 28 | OHHTTPStubs: 1e21c7d2c084b8153fc53d48400d8919d2d432d0 29 | 30 | PODFILE CHECKSUM: 8e6d7727bc494546363e0c7b4bb5c24a0e69cf70 31 | 32 | COCOAPODS: 1.7.3 33 | -------------------------------------------------------------------------------- /Pods/OHHTTPStubs/LICENSE: -------------------------------------------------------------------------------- 1 | - MIT LICENSE - 2 | 3 | Copyright (c) 2012 Olivier Halligon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 4.10.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Kingfisher : NSObject 3 | @end 4 | @implementation PodsDummy_Kingfisher 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "Kingfisher.h" 14 | 15 | FOUNDATION_EXPORT double KingfisherVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[]; 17 | 18 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher.modulemap: -------------------------------------------------------------------------------- 1 | framework module Kingfisher { 2 | umbrella header "Kingfisher-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Kingfisher/Kingfisher.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kingfisher 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/OHHTTPStubs/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 6.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 6.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_OHHTTPStubs : NSObject 3 | @end 4 | @implementation PodsDummy_OHHTTPStubs 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "Compatibility.h" 14 | #import "OHHTTPStubs.h" 15 | #import "OHHTTPStubsResponse.h" 16 | #import "OHHTTPStubsResponse+JSON.h" 17 | #import "NSURLRequest+HTTPBodyTesting.h" 18 | #import "OHPathHelpers.h" 19 | #import "Compatibility.h" 20 | 21 | FOUNDATION_EXPORT double OHHTTPStubsVersionNumber; 22 | FOUNDATION_EXPORT const unsigned char OHHTTPStubsVersionString[]; 23 | 24 | -------------------------------------------------------------------------------- /Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.modulemap: -------------------------------------------------------------------------------- 1 | framework module OHHTTPStubs { 2 | umbrella header "OHHTTPStubs-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/OHHTTPStubs/OHHTTPStubs.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Foundation" 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/OHHTTPStubs 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Pods-AutocompleteClientTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Pods-AutocompleteClientTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## OHHTTPStubs 5 | 6 | - MIT LICENSE - 7 | 8 | Copyright (c) 2012 Olivier Halligon 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | Generated by CocoaPods - https://cocoapods.org 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Pods-AutocompleteClientTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_AutocompleteClientTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_AutocompleteClientTests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Pods-AutocompleteClientTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_AutocompleteClientTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_AutocompleteClientTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Pods-AutocompleteClientTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs/OHHTTPStubs.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs/OHHTTPStubs.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs" 7 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Foundation" -framework "OHHTTPStubs" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Pods-AutocompleteClientTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_AutocompleteClientTests { 2 | umbrella header "Pods-AutocompleteClientTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-AutocompleteClientTests/Pods-AutocompleteClientTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs/OHHTTPStubs.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs/OHHTTPStubs.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/OHHTTPStubs" 7 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Foundation" -framework "OHHTTPStubs" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserApplication/Pods-UserApplication-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserApplication/Pods-UserApplication-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Kingfisher 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2018 Wei Wang 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | 29 | Generated by CocoaPods - https://cocoapods.org 30 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserApplication/Pods-UserApplication-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_UserApplication : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_UserApplication 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserApplication/Pods-UserApplication-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_UserApplicationVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_UserApplicationVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserApplication/Pods-UserApplication.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 7 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Kingfisher" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserApplication/Pods-UserApplication.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_UserApplication { 2 | umbrella header "Pods-UserApplication-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-UserApplication/Pods-UserApplication.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" 7 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" -framework "Kingfisher" 8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 9 | PODS_BUILD_DIR = ${BUILD_DIR} 10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_empty.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_constructor.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon_constructor@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon_constructor@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_empty.imageset/icon_constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/Resources/Assets.xcassets/icon_empty.imageset/icon_constructor.png -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_empty.imageset/icon_constructor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/Resources/Assets.xcassets/icon_empty.imageset/icon_constructor@2x.png -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_empty.imageset/icon_constructor@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/Resources/Assets.xcassets/icon_empty.imageset/icon_constructor@3x.png -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_error.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_error.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon_error@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon_error@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_error.imageset/icon_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/Resources/Assets.xcassets/icon_error.imageset/icon_error.png -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_error.imageset/icon_error@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/Resources/Assets.xcassets/icon_error.imageset/icon_error@2x.png -------------------------------------------------------------------------------- /Resources/Assets.xcassets/icon_error.imageset/icon_error@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/Resources/Assets.xcassets/icon_error.imageset/icon_error@3x.png -------------------------------------------------------------------------------- /Resources/constructor-io-error-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/Resources/constructor-io-error-icon.png -------------------------------------------------------------------------------- /SearchFWTestApp/SearchFWTestApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SearchFWTestApp/SearchFWTestApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SearchFWTestApp/SearchFWTestApp/Assets.xcassets/Logo/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SearchFWTestApp/SearchFWTestApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /SearchFWTestApp/SearchFWTestAppTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SearchFWTestApp/SearchFWTestAppTests/SearchFWTestAppTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchFWTestAppTests.swift 3 | // Constructor.io 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import XCTest 10 | @testable import SearchFWTestApp 11 | 12 | class SearchFWTestAppTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_cart.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_cart.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon_cart@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon_cart@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_cart.imageset/icon_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_cart.imageset/icon_cart.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_cart.imageset/icon_cart@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_cart.imageset/icon_cart@2x.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_cart.imageset/icon_cart@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_cart.imageset/icon_cart@3x.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_clock.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_clock.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_clock.imageset/icon_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_clock.imageset/icon_clock.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_error_yellow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_error_yellow.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_error_yellow.imageset/icon_error_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_error_yellow.imageset/icon_error_yellow.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_filter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_filter.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_filter.imageset/icon_filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_filter.imageset/icon_filter.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_gear.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon-gear.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_gear.imageset/icon-gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_gear.imageset/icon-gear.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_help.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_help.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_help.imageset/icon_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_help.imageset/icon_help.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "constructor-io-logo.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_logo.imageset/constructor-io-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_logo.imageset/constructor-io-logo.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_sign_error.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_sign_error.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_sign_error.imageset/icon_sign_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_sign_error.imageset/icon_sign_error.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_sort.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_sort.jpg", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_sort.imageset/icon_sort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_sort.imageset/icon_sort.jpg -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_star.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_star.png", 6 | "scale" : "1x" 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 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/icon_star.imageset/icon_star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/icon_star.imageset/icon_star.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/img_logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "img_logo.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/img_logo.imageset/img_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/img_logo.imageset/img_logo.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/sort_ascending.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "arrow_up.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/sort_ascending.imageset/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/sort_ascending.imageset/arrow_up.png -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/sort_descending.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "arrow_down.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UserApplication/Assets.xcassets/sort_descending.imageset/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/UserApplication/Assets.xcassets/sort_descending.imageset/arrow_down.png -------------------------------------------------------------------------------- /UserApplication/Common/BadgeView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BadgeView.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | class BadgeView: UIView { 12 | 13 | private var label: UILabel 14 | 15 | init(){ 16 | self.label = UILabel(frame: .zero) 17 | super.init(frame: .zero) 18 | self.backgroundColor = UIColor.red 19 | self.clipsToBounds = true 20 | 21 | self.label.backgroundColor = .clear 22 | self.label.textAlignment = .center 23 | self.label.translatesAutoresizingMaskIntoConstraints = false 24 | self.label.textColor = UIColor.white 25 | self.label.adjustsFontSizeToFitWidth = true 26 | self.label.baselineAdjustment = .alignCenters 27 | 28 | self.label.font = UIFont.systemFont(ofSize: 10) 29 | 30 | self.addSubview(label) 31 | self.label.pinToSuperviewTop(2) 32 | self.label.pinToSuperviewBottom(2) 33 | self.label.pinToSuperviewLeft(2) 34 | self.label.pinToSuperviewRight(2) 35 | } 36 | 37 | func setValue(text: String){ 38 | self.label.text = text 39 | self.label.layoutIfNeeded() 40 | self.label.setNeedsDisplay() 41 | } 42 | 43 | required init?(coder aDecoder: NSCoder) { 44 | fatalError("init(coder:) has not been implemented") 45 | } 46 | 47 | override func layoutSubviews() { 48 | super.layoutSubviews() 49 | self.layer.cornerRadius = self.frame.size.height/2 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /UserApplication/Common/Constructor/ConstructorIOProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConstructorIOProvider.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | 12 | protocol ConstructorIOProvider{ 13 | func provideConstructorInstance() -> ConstructorIO 14 | } 15 | -------------------------------------------------------------------------------- /UserApplication/CustomHighlighting/CustomAttributesProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomAttributesProvider.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import ConstructorAutocomplete 11 | 12 | class CustomAttributesProvider: CIOHighlightingAttributesProvider { 13 | 14 | func defaultSubstringAttributes() -> [NSAttributedString.Key: Any] { 15 | return [NSAttributedString.Key.foregroundColor: UIColor.darkGray, NSAttributedString.Key.font: UIFont(name: "Optima-Regular", size: 15)!] 16 | } 17 | 18 | func highlightedSubstringAttributes() -> [NSAttributedString.Key: Any] { 19 | return [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont(name: "Optima-Bold", size: 15)!] 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /UserApplication/CustomViews/Cell/Class/CustomTableViewCellTwo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTableViewCellTwo.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import ConstructorAutocomplete 11 | 12 | class CustomTableViewCellTwo: UITableViewCell, CIOAutocompleteCell { 13 | 14 | func setup(result: CIOAutocompleteResult, searchTerm: String, highlighter: CIOHighlighter) { 15 | if let group = result.group{ 16 | let groupString = NSMutableAttributedString() 17 | groupString.append(NSAttributedString(string: " in ", attributes: highlighter.attributesProvider.defaultSubstringAttributes())) 18 | groupString.append(NSAttributedString(string: group.displayName, attributes: highlighter.attributesProvider.highlightedSubstringAttributes())) 19 | self.textLabel?.attributedText = groupString 20 | 21 | self.imageView?.image = nil 22 | }else{ 23 | self.textLabel?.attributedText = highlighter.highlight(searchTerm: searchTerm, itemTitle: result.result.value) 24 | self.imageView?.image = UIImage(named: "icon_clock") 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /UserApplication/CustomViews/Error/CustomErrorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomErrorView.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import ConstructorAutocomplete 11 | 12 | class CustomErrorView: UIView, CIOErrorView { 13 | 14 | @IBOutlet weak var labelError: UILabel! 15 | 16 | func asView() -> UIView { 17 | return self 18 | } 19 | 20 | func setErrorString(errorString: String) { 21 | self.labelError.text = errorString 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /UserApplication/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIViewControllerBasedStatusBarAppearance 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /UserApplication/Screens/Cart/Logic/CartItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CartItem.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | struct CartItem: Codable{ 12 | let title: String 13 | let imageURL: String 14 | let price: Double 15 | var totalPrice: Double { 16 | return self.price * Double(self.quantity) 17 | } 18 | var quantity: Int 19 | 20 | } 21 | -------------------------------------------------------------------------------- /UserApplication/Screens/Cart/UI/CartItemTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CartItemTableViewCell.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | class CartItemTableViewCell: UITableViewCell { 12 | 13 | @IBOutlet weak var labelTitle: UILabel! 14 | @IBOutlet weak var labelQuantity: UILabel! 15 | @IBOutlet weak var labelTotalPrice: UILabel! 16 | @IBOutlet weak var imageViewProduct: UIImageView! 17 | 18 | func setup(_ model: CartItemViewModel){ 19 | self.labelTitle.text = model.title 20 | self.labelQuantity.text = model.quantity.string 21 | self.labelTotalPrice.text = model.singleItemPrice 22 | self.imageViewProduct.kf.setImage(with: URL(string: model.imageURL)) 23 | 24 | self.labelTitle.font = UIFont.appFontSemiBold(18) 25 | self.labelTotalPrice.font = UIFont.appFont(17) 26 | self.labelTotalPrice.adjustsFontSizeToFitWidth = true 27 | self.labelQuantity.font = UIFont.appFont(11) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /UserApplication/Screens/Cart/ViewModel/CartItemViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CartItemViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | struct CartItemViewModel { 12 | let title: String 13 | let imageURL: String 14 | let singleItemPrice: String 15 | let totalPrice: String 16 | var quantity: Quantity 17 | 18 | init(item: CartItem){ 19 | self.title = item.title 20 | self.quantity = Quantity(value: item.quantity) 21 | self.imageURL = item.imageURL 22 | self.singleItemPrice = String(format: "$%.2f",item.price) 23 | self.totalPrice = String(format: "$%.2f",item.totalPrice) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /UserApplication/Screens/Cart/ViewModel/CartViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CartViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | 12 | class CartViewModel { 13 | 14 | var items: [CartItemViewModel] 15 | let cart: Cart 16 | let constructor: ConstructorIO 17 | 18 | var totalPrice: String{ 19 | return String(format: "$%.02f", cart.items.map({ $0.totalPrice }).reduce(0, +)) 20 | } 21 | 22 | init(cart: Cart, constructor: ConstructorIO){ 23 | self.cart = cart 24 | self.constructor = constructor 25 | self.items = [] 26 | self.reloadItems() 27 | } 28 | 29 | func reloadItems(){ 30 | self.items = cart.items.map{ CartItemViewModel(item: $0)} 31 | } 32 | 33 | func updateQuantity(newValue: Int, for index: Int) -> CartItemViewModel?{ 34 | if let cartItem = self.cart.updateQuantity(newValue: newValue, for: index){ 35 | let viewModel = CartItemViewModel(item: cartItem) 36 | items[index] = viewModel 37 | return viewModel 38 | }else{ 39 | self.items.remove(at: index) 40 | return nil 41 | } 42 | } 43 | 44 | func removeItemAtIndex(_ index: Int){ 45 | self.cart.items.remove(at: index) 46 | self.reloadItems() 47 | } 48 | 49 | func removeAllItems(){ 50 | self.cart.items = [] 51 | self.reloadItems() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /UserApplication/Screens/Cart/ViewModel/Quantity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quantity.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | struct Quantity{ 12 | var value: Int 13 | var string: String{ 14 | return "QTY. \(self.value)" 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /UserApplication/Screens/Details/ViewModel/DetailsViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailsViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | struct DetailsViewModel{ 13 | let title: String 14 | let price: Double 15 | var priceString: String{ 16 | return "$\(self.price)" 17 | } 18 | let image: UIImage? 19 | let imageURL: String 20 | let description: String 21 | 22 | var titlePrice: String{ 23 | return "\(self.title)\n\n\(self.priceString)" 24 | } 25 | 26 | let cart: Cart 27 | 28 | } 29 | -------------------------------------------------------------------------------- /UserApplication/Screens/Filters/Delegate/FiltersSelectionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FiltersDelegate.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | 12 | protocol FiltersSelectionDelegate: AnyObject{ 13 | func didSelect(filters: [Filter]) 14 | } 15 | -------------------------------------------------------------------------------- /UserApplication/Screens/Filters/UI/Cells/FilterTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterTableViewCell.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | class FilterTableViewCell: UITableViewCell { 12 | 13 | @IBOutlet weak var labelTitle: UILabel! 14 | 15 | override func awakeFromNib() { 16 | super.awakeFromNib() 17 | // Initialization code 18 | } 19 | 20 | override func setSelected(_ selected: Bool, animated: Bool) { 21 | super.setSelected(selected, animated: animated) 22 | 23 | // Configure the view for the selected state 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /UserApplication/Screens/Filters/UI/Header/Delegate/FilterHeaderDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterHeaderDelegate.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | 11 | protocol FilterHeaderDelegate: class{ 12 | func didTapOnSortView() 13 | func didTapOnFilterView() 14 | } 15 | -------------------------------------------------------------------------------- /UserApplication/Screens/Filters/UI/Header/FilterHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterHeaderView.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | class FilterHeaderView: UIView { 12 | 13 | weak var tapDelegate: FilterHeaderDelegate? 14 | @IBOutlet weak var imageViewSort: UIImageView! 15 | @IBOutlet weak var labelSort: UILabel! 16 | @IBOutlet weak var labelFilter: UILabel! 17 | @IBOutlet weak var viewFilter: UIView! 18 | @IBOutlet weak var viewSort: UIView! 19 | 20 | class func instantiateFromNib() -> FilterHeaderView{ 21 | let v = UINib(nibName: "FilterHeaderView", bundle: nil).instantiate(withOwner: nil, options: nil).first as! FilterHeaderView 22 | v.translatesAutoresizingMaskIntoConstraints = false 23 | return v 24 | } 25 | 26 | override func awakeFromNib() { 27 | super.awakeFromNib() 28 | 29 | self.viewFilter.isUserInteractionEnabled = true 30 | self.viewSort.isUserInteractionEnabled = true 31 | 32 | self.viewFilter.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapOnViewFilter))) 33 | self.viewSort.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapOnViewSort))) 34 | 35 | self.layer.borderWidth = 0.6 36 | self.layer.borderColor = UIColor.darkGray.withAlphaComponent(0.5).cgColor 37 | } 38 | 39 | @objc 40 | func didTapOnViewSort(){ 41 | self.tapDelegate?.didTapOnSortView() 42 | } 43 | 44 | @objc 45 | func didTapOnViewFilter(){ 46 | self.tapDelegate?.didTapOnFilterView() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /UserApplication/Screens/Filters/ViewModel/FacetOptionViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FacetOptonViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | 12 | struct FacetOptionViewModel{ 13 | let value: String 14 | let title: String 15 | var selected: Bool 16 | } 17 | 18 | extension FacetOptionViewModel{ 19 | init(option: CIOFilterFacetOption){ 20 | self.init(value: option.value, title: option.displayName, selected: false) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /UserApplication/Screens/Filters/ViewModel/FacetViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Facet.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import ConstructorAutocomplete 11 | 12 | class FacetViewModel { 13 | let title: String 14 | var options: [FacetOptionViewModel] 15 | 16 | convenience init(facet: CIOFilterFacet){ 17 | self.init(filterName: facet.displayName, options: facet.options.map(FacetOptionViewModel.init)) 18 | } 19 | 20 | init(filterName: String, options: [FacetOptionViewModel]){ 21 | self.title = filterName 22 | self.options = options 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /UserApplication/Screens/Filters/ViewModel/FiltersViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FiltersViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import ConstructorAutocomplete 11 | 12 | class FiltersViewModel { 13 | let filters: [FacetViewModel] 14 | var changed: Bool = false 15 | weak var delegate: FiltersSelectionDelegate? 16 | 17 | var selectedFilters: [Filter]{ 18 | return self.filters.reduce([Filter]()) { res, next in 19 | return res + next.options.filter{ $0.selected } 20 | .map({ return (key: next.title, value: $0.value) as Filter }) 21 | } 22 | } 23 | 24 | init(filters: [FacetViewModel]){ 25 | self.filters = filters 26 | } 27 | 28 | func toggle(indexPath: IndexPath){ 29 | self.changed = true 30 | self.filters[indexPath.section].options[indexPath.row].selected.toggle() 31 | } 32 | 33 | func dismiss(){ 34 | if self.changed{ 35 | self.delegate?.didSelect(filters: self.selectedFilters) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /UserApplication/Screens/Search/UI/SearchCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchCollectionViewCell.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import Kingfisher 11 | 12 | class SearchCollectionViewCell: UICollectionViewCell { 13 | 14 | @IBOutlet weak var imageView: UIImageView! 15 | @IBOutlet weak var labelProductName: UILabel! 16 | @IBOutlet weak var labelPrice: UILabel! 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | 21 | self.contentView.layer.borderColor = UIColor.black.withAlphaComponent(0.2).cgColor 22 | self.contentView.layer.borderWidth = 1 23 | self.contentView.layer.masksToBounds = true 24 | self.contentView.clipsToBounds = true 25 | } 26 | 27 | func setup(viewModel: SearchResultViewModel){ 28 | self.labelProductName.text = viewModel.title 29 | self.labelPrice.text = viewModel.priceString 30 | 31 | self.imageView.kf.setImage(with: URL(string: viewModel.imageURL), placeholder: viewModel.fallbackImage()) 32 | } 33 | 34 | override func prepareForReuse() { 35 | super.prepareForReuse() 36 | self.imageView.kf.cancelDownloadTask() 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /UserApplication/Screens/Search/UI/SearchTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchTableViewCell.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | class SearchTableViewCell: UITableViewCell { 12 | 13 | override func awakeFromNib() { 14 | super.awakeFromNib() 15 | // Initialization code 16 | } 17 | 18 | override func setSelected(_ selected: Bool, animated: Bool) { 19 | super.setSelected(selected, animated: animated) 20 | 21 | // Configure the view for the selected state 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /UserApplication/Screens/Search/UI/SearchTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /UserApplication/Screens/Search/ViewModel/SearchResultViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | import UIKit 12 | 13 | public struct SearchResultViewModel{ 14 | 15 | public let title: String 16 | public let price: Double 17 | public let priceString: String 18 | public let imageURL: String 19 | public let description: String 20 | public let fallbackImage: () -> UIImage 21 | 22 | public init(searchResult: CIOResult){ 23 | self.title = searchResult.value 24 | self.price = searchResult.data.metadata["price"] as? Double ?? 0.00 25 | self.imageURL = searchResult.data.imageURL ?? "" 26 | self.fallbackImage = { return UIImage(named: "icon_logo")! } 27 | 28 | self.description = searchResult.data.metadata["description"] as? String ?? "" 29 | self.priceString = "$\(self.price)" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /UserApplication/Screens/Sort/Delegate/SortSelectionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SortSelectionDelegate.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | 12 | protocol SortSelectionDelegate: AnyObject{ 13 | func didSelect(sortOption: CIOSortOption?) 14 | } 15 | -------------------------------------------------------------------------------- /UserApplication/Screens/Sort/UI/SortOptionTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SortOptionTableViewCell.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | 11 | class SortOptionTableViewCell: UITableViewCell { 12 | 13 | @IBOutlet weak var labelSort: UILabel! 14 | @IBOutlet weak var imageViewSort: UIImageView! 15 | 16 | override func awakeFromNib() { 17 | super.awakeFromNib() 18 | self.imageView?.contentMode = .scaleAspectFit 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /UserApplication/Screens/Sort/UI/UIImage/UIImage+Sort.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Sort.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | import UIKit 12 | 13 | extension UIImage{ 14 | class func imageSortAscending() -> UIImage{ 15 | return UIImage(named: "sort_ascending")! 16 | } 17 | 18 | class func imageSortDescending() -> UIImage{ 19 | return UIImage(named: "sort_descending")! 20 | } 21 | 22 | class func imageForSortOrder(_ sortOrder: CIOSortOrder) -> UIImage{ 23 | switch sortOrder { 24 | case .ascending: 25 | return self.imageSortAscending() 26 | case .descending: 27 | return self.imageSortDescending() 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /UserApplication/Screens/Sort/ViewModel/SortOptionViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SortOptionViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ConstructorAutocomplete 12 | 13 | struct SortOptionViewModel{ 14 | var model: CIOSortOption 15 | 16 | let displayName: String 17 | let image: UIImage? 18 | var selected: Bool 19 | 20 | init(option: CIOSortOption){ 21 | self.model = option 22 | self.displayName = option.displayName 23 | self.image = UIImage.imageForSortOrder(option.sortOrder) 24 | self.selected = false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /UserApplication/Screens/Sort/ViewModel/SortViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SortViewModel.swift 3 | // UserApplication 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import ConstructorAutocomplete 11 | 12 | class SortViewModel{ 13 | var items: [SortOptionViewModel] 14 | var selectedItem: SortOptionViewModel?{ 15 | get{ 16 | return self.items.first(where: { $0.selected }) 17 | } 18 | } 19 | var changed: Bool 20 | 21 | weak var delegate: SortSelectionDelegate? 22 | 23 | init(items: [SortOptionViewModel]){ 24 | self.items = items 25 | self.changed = false 26 | } 27 | 28 | func toggle(indexPath: IndexPath){ 29 | self.changed = true 30 | for idx in 0.. UIColor { 13 | return self.RGBA(red, green: green, blue: blue, alpha: 255) 14 | } 15 | 16 | class func RGBA(_ red: Int, green: Int, blue: Int, alpha: CGFloat) -> UIColor { 17 | return UIColor(red: CGFloat(red) / 255.0, green: CGFloat(green)/255.0, blue: CGFloat(blue)/255.0, alpha: alpha) 18 | } 19 | 20 | class func hex(rgb: Int) -> UIColor { 21 | return self.RGB((rgb >> 16) & 0xFF, green: (rgb >> 8) & 0xFF, blue: rgb & 0xFF) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UserApplication/Utils/UI/UIFont+AppFonts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIFont+AppFonts.swift 3 | // UserApplication 4 | // 5 | // Created by Nikola Markovic on 10/25/19. 6 | // Copyright © 2019 xd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIFont{ 12 | static func appFontSemiBold(_ size: CGFloat) -> UIFont{ 13 | return UIFont.systemFont(ofSize: size, weight: .semibold) 14 | } 15 | 16 | static func appFontBold(_ size: CGFloat) -> UIFont{ 17 | return UIFont.systemFont(ofSize: size, weight: .bold) 18 | } 19 | 20 | static func appFont(_ size: CGFloat) -> UIFont{ 21 | return UIFont.systemFont(ofSize: size) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UserApplicationTests/DataSource/AutocompleteDataSourceWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteDataSourceWrapper.swift 3 | // UserApplicationTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import ConstructorAutocomplete 11 | 12 | //class AutocompleteDataSourceWrapper: CIOAutocompleteDataSource { 13 | // 14 | // @objc 15 | // optional func customCellNib() -> UINib 16 | // 17 | // @objc 18 | // optional func customCellClass() -> AnyClass 19 | // 20 | // @objc 21 | // optional func styleSearchBar(searchBar: UISearchBar) 22 | // 23 | // @objc 24 | // optional func styleResultLabel(label: UILabel) 25 | // 26 | // @objc 27 | // optional func styleResultCell(cell: UITableViewCell) 28 | // 29 | // @objc 30 | // optional func fontNormal() -> UIFont 31 | // 32 | // @objc 33 | // optional func fontBold() -> UIFont 34 | // 35 | // @objc 36 | // optional func rowHeight() -> CGFloat 37 | // 38 | // @objc 39 | // optional func searchBarPlaceholder() -> String 40 | // 41 | // @objc 42 | // optional func backgroundView() -> UIView? 43 | // 44 | // @objc 45 | // optional func errorView() -> UIView? 46 | //} 47 | -------------------------------------------------------------------------------- /UserApplicationTests/Delegate/AutocompleteDelegateWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteDelegateWrapper.swift 3 | // UserApplicationTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import UIKit 10 | import ConstructorAutocomplete 11 | 12 | class AutocompleteDelegateWrapper: CIOAutocompleteDelegate { 13 | 14 | var onSelect: ((_ result: CIOAutocompleteResult) -> Void)? 15 | var onSearchPerformed: ((_ searchTerm: String) -> Void)? 16 | var onLoad: (() -> Void)? 17 | var onWillAppear: (() -> Void)? 18 | 19 | func autocompleteController(controller: CIOAutocompleteViewController, didSelectResult result: CIOAutocompleteResult) { 20 | self.onSelect?(result) 21 | } 22 | 23 | func autocompleteController(controller: CIOAutocompleteViewController, didPerformSearch searchTerm: String) { 24 | self.onSearchPerformed?(searchTerm) 25 | } 26 | 27 | func autocompleteControllerWillAppear(controller: CIOAutocompleteViewController) { 28 | self.onWillAppear?() 29 | } 30 | 31 | func autocompleteControllerDidLoad(controller: CIOAutocompleteViewController) { 32 | self.onLoad?() 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /UserApplicationTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /UserApplicationTests/Utils/CIOAutocompleteViewController+Show.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AutocompleteViewController+Show.swift 3 | // UserApplicationTests 4 | // 5 | // Copyright (c) Constructor.io Corporation. All rights reserved. 6 | // http://constructor.io/ 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ConstructorAutocomplete 12 | 13 | extension CIOAutocompleteViewController { 14 | 15 | class func instantiate() -> CIOAutocompleteViewController { 16 | let viewController = CIOAutocompleteViewController(config: TestConstants.testConfig) 17 | return viewController 18 | } 19 | 20 | func showInNewWindow() { 21 | let window = UIWindow(frame: UIScreen.main.bounds) 22 | window.rootViewController = self 23 | 24 | window.makeKeyAndVisible() 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /coverage.all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Create coverage reports for all files 4 | rm -rf coverage-reports 5 | mkdir coverage-reports 6 | slather coverage --html --show --output-directory coverage-reports --ignore AutocompleteClientTests/\* -------------------------------------------------------------------------------- /coverage.core.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Create coverage reports for core (non-UI) code 4 | rm -rf coverage-reports 5 | mkdir coverage-reports 6 | slather coverage --html --show --output-directory coverage-reports --ignore AutocompleteClientTests/\* --ignore AutocompleteClient/FW/UI/\* --ignore AutocompleteClient/Utils/\*\*/UI\* -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 94% 23 | 24 | 25 | 94% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.constructorautocomplete 7 | CFBundleName 8 | ConstructorAutocomplete 9 | DocSetPlatformFamily 10 | constructorautocomplete 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 94% 23 | 24 | 25 | 94% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/Documents/img/spinner.gif -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/docsets/ConstructorAutocomplete.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/ConstructorAutocomplete.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/docsets/ConstructorAutocomplete.tgz -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/img/gh.png -------------------------------------------------------------------------------- /docs/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Constructor-io/constructorio-client-swift/43925c352742bb3bf3104c186a1e76935687aa00/docs/img/spinner.gif --------------------------------------------------------------------------------